2016-01-10 2 views
5

Я конвертирую программу из C++ в C с помощью Microsoft Visual Studio. Это приложение для Windows, но я не думаю, что это относится к этому вопросу.Явное объявление указателя функции, а не указателя данных

Я использую переключатель /W4 для включения дополнительных предупреждающих сообщений. Я хотел бы, чтобы моя программа компилировалась без предупреждений. Программа компилируется и работает нормально. Это всего лишь предупреждение.

Прежде, чем программа была C++, она скомпилирована без предупреждений, но теперь, когда я как можно лучше ее преобразовал в C, появляется предупреждение, что я не знаю, как с этим бороться.

Вот соответствующий код. Идея состоит в том, что я создаю систему меню для графического интерфейса. Каждое меню содержит набор элементов меню, и каждый пункт меню содержит указатель функции, который представляет действие, которое будет выполняться, когда пользователь выбирает этот пункт меню.

typedef struct MENUITEM 
{ 
    wchar_t* Name; 
    void* Action; 
} MENUITEM; 

typedef struct MENU 
{ 
    wchar_t* Name; 
    uint8_t SelectedItem; 
    uint8_t ItemCount; 
    MENUITEM** Items; 
} MENU; 

В другом месте в программе, это код, который обрабатывает событие, когда пользователь выбирает пункт меню:

void(*FP) (void) = NULL; 
FP = (void(*)())MyMenu.Items[MyMenu.SelectedItem]->Action; 
FP(); 

Ниже приведены предупреждения компилятора, которые генерируются:

C4152 нестандартное расширение, преобразование указателя функции/данных в выражении

И

C4113 'недействительным (__cdecl *)()' отличается в списках параметров из 'пустоты (__cdecl *) (ничтожной)'

MSDN documentation для предупреждающего сообщения C4152 гласит:

Указатель функции преобразуется в указатель данных или из него. Это преобразование разрешено в расширениях Microsoft (/ Ze), но не под ANSI C.

ОК, поэтому я думаю, что это объясняет, почему оно не выдавало предупреждение как C++, но при компиляции как C оно делает. Но я не знаю, как с этим бороться. Честно говоря, я до сих пор не осознавал, что существует разница между указателем на функцию и указателем данных.

Я не могу понять, как изменить объявление моего указателя на функцию, чтобы он был явным компилятору, что это указатель на функцию, а не указатель данных.

ответ

3

Вы забыли void в гипсе. Это то, о чем говорит C4113.

Вы можете избежать литого вообще, объявляя Action в качестве указателя функции: ответ

void (*Action)(void); 
+1

Danny_ds был хорош, но ИМО этот ответ был лучшим. Теперь код не только компилируется без предупреждений, но также позволяет мне исключить дополнительное локальное объявление FP в моем коде и использовать только «MyMenu».Элементы [MyMenu.SelectedItem] -> Action(); ' –

+0

@RyanRies. Просто, чтобы быть ясным: что, конечно, необязательная локальная декларация не требуется - она ​​была там для ясности, чтобы показать использование. Использование typedef для указателей функций обычно является хорошей идеей. –

+1

@ Danny_ds I See. Спасибо. Оба ваших ответа ценны. Я думаю, что оба ваших ответа, когда они были сделаны в сочетании, помогли ему «щелкнуть» для меня. Хотел бы я принять их обоих. –

5

Вы, наверное, это нужно (с typedef):

typedef void(*FP) (void); 

typedef struct MENUITEM 
{ 
    wchar_t* Name; 
    FP Action; 
} MENUITEM; 

int main() { 

    MENUITEM it; 
    // ... more code 

    FP fp = it.Action; 
    fp(); 

    return 0; 
} 
Смежные вопросы