ошибка: неверное преобразование из 'void (*) ()' в 'void (*) ()' - что? - PullRequest
6 голосов
/ 17 февраля 2011

Я пытаюсь передать функцию обратного вызова из C ++ в OpenGL (C API):

gluQuadricCallback(qobj, GLU_ERROR, errorCallback);

, где errorCallback - функция в файле, скомпилированная в виде кода C ++, и объявленная как

void errorCallback();

Код компилируется чисто с g ++ 4.4 на Linux, но выдает следующую ошибку с mingw32 g ++ 4.4 на Windows:

..\glwidget.cpp:172: error: invalid conversion from 'void (*)()' to 'void (*)()'

..\glwidget.cpp:172: error:   initializing argument 3 of 'void gluQuadricCallback(GLUquadric*, GLenum, void (*)())'

Это какая-то проблема смешения C и C ++? Как я могу решить это?

ОБНОВЛЕНИЕ: void GLAPIENTRY errorCallback(); также не компилируется :(
.. \ glwidget.cpp: 129: ошибка: ожидаемый инициализатор до 'errorCallback'
Теперь почти наверняка это проблема соглашения о вызовах, и не имеет ничего общего с связью C , см. Комментарии ниже в ответе Томаса.

ОБНОВЛЕНИЕ 2: Мне кажется, я просто столкнулся с грязной проблемой OpenGL, касающейся GLAPIENTRY, APIENTRY и _GLUfuncptr. Вот ОЧЕНЬ ДЛИННОЕ обсуждение проблем переносимости:
http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/2007-October/003023.html

1 Ответ

7 голосов
/ 17 февраля 2011

Если это все, что вы получаете за ошибку, это довольно хреновое сообщение. Это проблема с соглашениями о вызовах.

Из моего glu.h:

GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);

_GLUfuncptr определяется как:

typedef void (GLAPIENTRYP _GLUfuncptr)();

с

#ifndef GLAPIENTRYP
#define GLAPIENTRYP GLAPIENTRY *
#endif

#ifndef GLAPIENTRY
#if defined(_MSC_VER) || defined(__MINGW32__)
#define GLAPIENTRY __stdcall
#else
#define GLAPIENTRY
#endif
#endif

Это объясняет разницу между Linux и Mingw.

Исходя из этого, вы можете подумать, что вам нужно объявить свой обратный вызов как

void GLAPIENTRY errorCallback();

и __stdcall будут надеты на него, когда это уместно.

Однако, как отмечает Али в комментариях ниже, добавление GLAPIENTRY к подписи обратного вызова не всегда работает. Кажется, что GLU 1.3 spec просто указывает, что void (*func)() принимается. Поскольку некоторые реализации требуют взамен _GLUfuncptr, который включает в себя требование GLAPIENTRY, а другие вообще не определяют GLAPIENTRY, здесь возникает проблема переносимости.

Возможный обходной путь может быть:

#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif

и, тем не менее, объявляем все обратные вызовы с помощью макроса GLAPIENTRY.

...