【问题标题】:Manually calling OpenGL functions手动调用OpenGL函数
【发布时间】:2016-07-30 23:09:33
【问题描述】:

我一直致力于创建一个 OpenGL 函数加载库,它可以帮助我在需要时调用 OpenGL 函数。

我有一个使用 glX 的 getProcAddress 函数。

void* getProcAddress(const char *name)
{
    auto pr = reinterpret_cast<void*>(glXGetProcAddress(
            reinterpret_cast<const unsigned char*>(name)));

    return pr;
}

这将返回 OpenGL 函数的地址。如果我不使用 reinterpret_casts,我会收到奇怪的编译器错误,这就是它们存在的原因。

然后我在头文件中定义一个 gl* 函数原型:

typedef void _GLACTIVETEXTURE(GLenum texture);

GLenum 在另一个头文件中定义为枚举。然后我在一个类中声明函数指针:

_GLACTIVETEXTURE glActiveTexture;

然后在一个名为 init 的函数中我会这样做:

void GLFunctions::init()
{
    glActiveTexture = (_GLACTIVETEXTURE)getProcAddress("glActiveTexture");
}

getProcAddress 函数可以自行编译,但上面的代码行无法编译。 GCC 抛出这个编译器错误:

error: invalid cast to function type ‘_GLACTIVETEXTURE {aka void(GLenum)}’

而且我不知道如何处理这种编译器错误。这是没有意义的,因为这是一个函数指针,而不是函数本身,除非我使用()。我不太确定这里的问题是什么;无论是我这边还是海湾合作委员会。目前还不清楚。我试过摆弄指针和空位,但一切都是徒劳的,并且出现了相同的错误消息。有谁知道这里发生了什么以及如何正确调用 OpenGL 函数?

【问题讨论】:

  • 我希望你知道 glew? glew.sourceforge.net
  • @H.Guijt 他想手动加载函数指针
  • @Akib Azmain 不要居高临下。指出替代解决方案并可能为某人节省大量工作并不是犯罪。

标签: c++ opengl gcc glx


【解决方案1】:

@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 的定义意识到了这一点,并已显式编写,以便它返回一个函数指针。但是因为函数指针不同于常规指针,所以不能将函数指针转换为常规指针。相反,您必须转换为目标函数指针类型,或者在赋值中转换函数指针变量左值(与 dlsym 一样)以匹配 glXGetProcAddress 的右值。

【讨论】:

  • 是否存在函数指针和常规指针实际上不同的实际系统?我不怀疑这个理论,只是想知道这是否是现实生活中的问题。
  • @RetoKoradi:几乎每个哈佛架构处理器。大多数 DSP 是哈佛架构,许多 µC 也是如此。
  • @RetoKoradi:例如看看 Analog Devices ADSP-219x DSP:它们使用 16 位可寻址数据存储器总线(即 16 位数据地址空间),但程序存储器总线有 24可寻址位(24 位地址空间)。因此,如果您将函数指针转换为常规数据指针,它将被截断。
  • 具有 dlsym [posix/unix] 或 GetProcAddress [Windows] 的系统必然具有统一的数据和代码指针。其他系统就不能这样说了。
  • 另外我认为如果数据指针和代码指针的大小不同(例如:如果数据指针是 32 位长而代码指针是 16 位长,那么这种“左值转换技巧”会导致问题,你在'fptr'之后覆盖了16位)
【解决方案2】:

您的typedef 错误。您正在为函数 type 而不是函数 pointer 创建别名。这是正确完成的方式:

typedef void (*_GLACTIVETEXTURE)(GLenum texture);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2019-08-28
    相关资源
    最近更新 更多