Я работал над созданием библиотеки загрузки функций OpenGL, которая поможет мне вызывать функции OpenGL, когда они мне понадобятся.
у меня есть getProcAddress
функция, которая использует glX.
void* getProcAddress(const char *name)
{
auto pr = reinterpret_cast<void*>(glXGetProcAddress(
reinterpret_cast<const unsigned char*>(name)));
return pr;
}
Это возвращает адрес функции OpenGL. Я получаю странные ошибки компилятора, если я не использую reinterpret_cast
Так вот почему они там.
Затем я определяю прототип функции gl * в заголовочном файле:
typedef void _GLACTIVETEXTURE(GLenum texture);
куда GLenum
определяется в другом заголовочном файле как enum. Затем я объявляю указатель на функцию в классе:
_GLACTIVETEXTURE glActiveTexture;
А затем в функции под названием init
Я делаю:
void GLFunctions::init()
{
glActiveTexture = (_GLACTIVETEXTURE)getProcAddress("glActiveTexture");
}
getProcAddress
Функция компилируется сама по себе, но приведенная выше строка кода не скомпилируется. GCC выдает эту ошибку компилятора:
error: invalid cast to function type ‘_GLACTIVETEXTURE {aka void(GLenum)}’
И я не знаю, как бороться с такой ошибкой компилятора. Это не имеет смысла, потому что это указатель на функцию, а не сама функция, если я не использую ()
, Я не совсем уверен, в чем здесь проблема; будь то с моей стороны или GCC. Не ясно. Я попытался поиграться с указателями и пустотами, но все напрасно, и появляется то же самое сообщение об ошибке. Кто-нибудь знает, что здесь происходит и как я могу правильно вызывать функции OpenGL?
Ваш typedef
неправильно. Вы создаете псевдоним для функции тип, не для функции указатель. Вот как это делается правильно:
typedef void (*_GLACTIVETEXTURE)(GLenum texture);
@nshct уже дал вам объяснение, почему компиляторы жалуются на ваш код. Что этот ответ не адресовал, почему ваш reinterpret_cast
было необходимо в первую очередь. Причина в том, что указатели на функции отличаются от обычных указателей, и вполне возможно, что sizeof(void*) != sizeof(void(*)(void))
то есть указатели на функции могут иметь совершенно иной диапазон значений и правил выравнивания, чем обычные указатели. Справочная страница для dlsym
адрес это подробно:
http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
обоснование
Стандарт ISO C не требует, чтобы указатели на функции могли быть
бросать взад и вперед к указателям на данные. Действительно, стандарт ISO C
не требует, чтобы объект типаvoid *
может содержать указатель на
функция. Реализации, поддерживающие расширение XSI, однако, делают
требуют, чтобы объект типаvoid *
может содержать указатель на
функция. Результат преобразования указателя на функцию в
указатель на другой тип данных (кромеvoid *
) все еще не определено,
тем не мение. Обратите внимание, что компиляторы, соответствующие стандарту ISO C,
требуется для создания предупреждения, если преобразование изvoid *
указатель
на указатель на функцию делается так:fptr = (int (*)(int))dlsym(handle, "my_function");
Из-за проблемы, отмеченной здесь, будущая версия может либо добавить новую
функция для возврата указателей на функции, или текущий интерфейс может быть
устарел в пользу двух новых функций: одна возвращает данные
указатели и другие, которые возвращают указатели на функции.
Из-за этого при использовании dlsym
необходимо использовать особый способ кастинга, а именно некоторую хитрость литья.
void *handle;
int (*fptr)(int);
/* open the needed object */
handle = dlopen("/usr/home/me/libfoo.so", RTLD_LOCAL | RTLD_LAZY);
/* find the address of function and data objects */
*(void **)(&fptr) = dlsym(handle, "my_function");
Определение glXGetProcAddress
знает об этом и был явно написан так, что он возвращает указатель на функцию. Но поскольку указатели на функции отличаются от обычных указателей, вы не должны преобразовывать указатель на функцию в обычный указатель. Вместо этого вы должны привести либо к типу указателя целевой функции, либо привести переменную указателя функции lvalue в присваивании (как в случае с dlsym), чтобы соответствовать значению glXGetProcAddress.