Вопрос по коллбекам, принимающим указатели void*

Тема в разделе "LANGS.C", создана пользователем osox, 11 май 2010.

  1. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    Всех приветствую, вопрос относится к Си без плюсов.
    вопрос относится к каллбекам которые принимают указатели void*
    есть у нас например модуль сторонний который для выполнения некоторых действий позволяет
    регистрировать каллбеки пусть сигнатура их такова
    Код (Text):
    1. void
    2. callback_func(void*, void*);
    так вот когда я пишу свою функцию каллбека чтобы передать ее адрес в дальнейшем
    я могу написать так
    Код (Text):
    1. void
    2. callback_func(void *it1, void *it2)
    3. {
    4.         char *pFirst = it1;  
    5.         char *pSecond = it2;
    6. }
    например этот модуль в аргументах каллбека передает указатели на строки
    но в отладчике MSVC внутри каллбека так просто не посмотреть значение параметров приходится или
    заводить переменные нужного типа или делать
    как то так
    Код (Text):
    1. ///////watch//////
    2. //(char*)it1,100//
    3. //(char*)it2,100//
    4. //////////////////
    но намного удобней сразу написать
    Код (Text):
    1. void
    2. callback_func(char *it1, char *it2)
    3. {
    4. }
    вот реальный пример сигнатура этого каллбека по идее такая
    Код (Text):
    1. int comp(const void *it1, const void *it2);
    но определяю я ее по другому
    Код (Text):
    1. int comp(const gchar *it1, const gchar *it2)
    2. {
    3.     int r;
    4.     r = strcmp(it1, it2);
    5.     return r == 1 ? -1 : r == -1 ? 1 : 0;
    6. }
    здесь особой нужды в параметрах нужного типа нет
    но это только пример
    при вызове каллбека в отладчике сразу видно значения параметров компиляция тоже без предупреждений проходит
    да и внутри каллбека заводить новые переменные нужного типа а потом присваивать им аргументы не надо
    или как то извращатся в окне watch
    вопрос чем это может вылезти боком в будущем и/или на других компиляторах платформах
    есть мысли что все приведения в подобных случаях в Си коде для того чтоб код
    без предупреждений и Си++ компилятором собирался но если совместимость с Си++
    не планируется можно ли так делать чем это плохо/чем может вылезти боком в будущем ?
     
  2. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    osox, вы умеете объяснять коротко и понятно. проблема будет в том, что вот такой код компилиться не будет:
    Код (Text):
    1. typedef int func_t(void*, void*);
    2.  
    3. int func(char* s1, char* s2)
    4. {
    5.   return 0;
    6. }
    7.  
    8. int main()
    9. {
    10.   func_t *p_func;
    11.   p_func = func;
    12. }
    при присваивании придётся явно преобразовывать тип. думаю, будет лучше, если во всех колбеках список аргументов будет тот, который заявлен. чтобы посмотреть, есть замечательные клавиши Ctrl+Alt+Q. или заведите в начале функции переменные типа char*.
     
  3. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    в том то и дело что собиратся ваш пример будет без предупреждений даже на /W4 самом высоком уровне предупреждений проверил и на MSVC 2010 и на LCC
     
  4. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Ну на всякий случай, для совместимости с с++ можете сделать типа так:
    Код (Text):
    1. typedef void (*callback_t)(void*, void*);
    2. void i_get_callback(int, callback_t);
    3. void my_callback(const char*, const char*);
    4. ...
    5. i_get_callback(0, (callback_t)my_callback);
    а вообще ни к чему не приведет, в си, типы демократичней автоматом кастуются =)
     
  5. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    Ну, знаете, даже такой код компилится, хотя и с предупреждением. Тем не менее, стек валится.

    Код (Text):
    1. typedef int __stdcall func_t(void*, void*);
    2.  
    3. int __stdcall func(char* s1)
    4. {
    5.   return 0;
    6. }
    7.  
    8. int main()
    9. {
    10.   func_t *p_func;
    11.   p_func = func;
    12.   (*p_func)(0, 0);
    13. }
     
  6. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    был бы __cdecl все прошло бы гладко а так можно самому подкорректировать :)
    Код (Text):
    1. typedef int __stdcall func_t(void*, void*);
    2.  
    3. int __stdcall func(char* s1)
    4. {
    5.   return 0;
    6. }
    7.  
    8. int main()
    9. {
    10.   func_t *p_func;
    11.   p_func = func;
    12.   __asm
    13.   {
    14.       push 0;
    15.       push 0;
    16.       call p_func;
    17.       add esp, 4;
    18.   }
    19. }
     
  7. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    osox, ну-ну. корректируйте.
    что касается формата вызовов - он нигде не определён. возьмите какой-нибудь BorlandC и всё свалится. Сам сталкивался: один и тот-же __fastcall VC и BC воспринимают по-разному. Какой формат вызова стоит по дефолту - х.з. Рассчитывать на это, а тем более, корректировать стек - это такая ж... Мало того, что кастыль, так ещё непортабельно. Делайте как вам посоветовали в самом начале:

    Код (Text):
    1. typedef int __stdcall func_t(void*, void*);
    2.  
    3. int __stdcall func(void* p1, void *p2)
    4. {
    5.   char *s1 = (char*)p1;
    6.   char *s2 = (char*)p2;
    7.  
    8.   return 0;
    9. }
    10.  
    11. int main()
    12. {
    13.   func_t *p_func;
    14.   p_func = func;
    15.   (*p_func)(0, 0);
    16. }
    за лишние переменные не бойтесь - компилятор от них избавится при оптимизации.
     
  8. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    maksim_
    это все аргументы ? я не спрашивал как мне делать я спрашивал почему и какие последствия могут быть вы же привели пример использующий __stdcall и при этом явно нарушающий конвенцию вызова что не имеет никакого отношения к моему вопросу он был совсем в другом или вы хотели показать
    что не все что компилится работает ? это я и без вас знаю надо по существу отвечать или не отвечать вовсе если есть что то по моему вопросу и по существу пишите
     
  9. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    osox. Больно надо. Не хотите слышать советов - не задавайте вопросы. Тем более так: "Знаеш ? Подскажи !", что соответствует правилам форума. Удачи.