我试图将回调函数从C++传递给OpenGL(C API):
gluQuadricCallback(qobj, GLU_ERROR, errorCallback);
其中
errorCallback
是编译为C++代码的文件中的函数,并声明为void errorCallback();
该代码在Linux上使用g++ 4.4可以干净地编译,但是在Windows上使用mingw32 g++ 4.4可以给出以下错误:
..\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链接无关,请参阅Thomas答案下面的注释。
更新2:在我看来,我刚遇到涉及
GLAPIENTRY
,APIENTRY
和_GLUfuncptr
的凌乱的OpenGL问题。这是关于可移植性问题的非常长时间的讨论:http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/2007-October/003023.html
最佳答案
如果仅这是您得到的错误,那是一条很糟糕的消息。这是调用约定的问题。
从我的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
的要求,但是其他实现根本没有定义GLAPIENTRY
,因此这里存在可移植性问题。可能的解决方法可能是:
#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif
并使用ojit_code宏声明所有回调。