在C中是否存在可以分配/转换为更具限制性的原型的通用函数指针?

she*_*lbc 12 c function-pointers dynamic-linking

我需要在运行时动态链接库并使用解析一系列函数dlsym.我的第一个想法是使用一个函数指针数组,通过利用char *表示符号名称的辅助数组,可以很容易地迭代.

但是,问题在于并非所有函数都使用相同的参数.有没有办法在数组中使用泛型函数指针,但是将它分配给限制性更强的函数指针原型?例如:

如果我需要解决这些功能:

int (*functionA)(int)
char (*functionB)(char,int)
Run Code Online (Sandbox Code Playgroud)

是否有可能做某些事情(伪似......)

void* functionList(...)[2] = {functionA, functionB};
Run Code Online (Sandbox Code Playgroud)

随着

char FuncNameA[] = "functionA";
char FuncNameB[] = "functionB";
char *functionNames[2] = {FuncNameA, FuncNameB};
Run Code Online (Sandbox Code Playgroud)

用于循环调用dlsym符号解析的目的

int i = 0;
for(; i<2; i++)
    functionList[i] = dlsym(DL_OPEN_HANDLE, functionNames[i]);
Run Code Online (Sandbox Code Playgroud)

其中DL_OPEN_HANDLE将由之前的调用定义dlopen.

Kei*_*son 13

C标准保证可以在void*不丢失信息的情况下将任何对象指针类型转换为和返回(意味着重新转换的指针将与原始指针进行比较).

函数指针没有这样的保证.例如,一种实现可以使void*64位和函数指针成为128位.

但是任何函数指针都可以转换为任何其他函数指针类型,然后再返回而不会丢失信息.

例如,您可以使用void(*)(void)通用函数指针类型:

typedef void (*funcptr)(void);
Run Code Online (Sandbox Code Playgroud)

在执行调用之前,必须转换回原始指针类型以避免未定义的行为.

另一方面,你正在使用dlsym(),它返回一个void*.我的理解是POSIX保证void*返回的dlsym()(如果name参数名称函数)可以转换为函数指针,可以用来调用函数.如果您关心的唯一功能是那些返回地址的功能dlsym(),那么您可以使用void*.

(POSIX以前保证,作为C标准的扩展,函数指针可以转换为void*后退.后来保证了这个保证.感谢Jonathan Leffler指出这一点.)

在任何情况下,使用函数指针来存储函数的地址可能会使代码更清晰.

  • 可悲的是,虽然过去曾经如此,但现在已不复存在了.第[2.12.3]节(http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_12)规定保证最高为POSIX 1003.1:2008,但修订版POSIX 1003.1:2013删除了该小节.另请参阅[0000074:指针类型问题](http://austingroupbugs.net/view.php?id=74) - 在问题的评论中也提到 - 详情.坦率地说,我不确定我们现在拥有的东西比以前更好. (2认同)

dbu*_*ush 5

您可能应该将列表定义为void *functionList[2],因为dlsym返回 a void *。一旦知道了自己拥有哪个函数,就可以将其转换为正确的类型。

void *functionList[2];

...

int (*functionA)(int) = (int(*)(int))functionList[0];
char (*functionB)(char,int) = (char(*)(char, int))functionList[1];
Run Code Online (Sandbox Code Playgroud)


eca*_*mur 5

dlsym返回类型为 的数据指针void *,但 POSIX 保证可以将其转换为适当类型的函数指针:

支持 XSI 扩展的实现 [...] 要求该类型的对象void *可以保存指向函数的指针。然而,将函数指针转换为另一种数据类型(除了void *)的指针的结果仍然是未定义的。

从 POSIX 版本 7 开始,所有实现(不仅仅是 XSI)都需要支持转换。

由于void *通过直接转换从指针到函数指针的转换可能会导致编译器警告,因此旧版本的 POSIX 建议通过别名执行转换:

int (*fptr)(int);
*(void **)(&fptr) = dlsym(handle, "my_function");
Run Code Online (Sandbox Code Playgroud)

在当前版本中,建议更改为:

int (*fptr)(int);
fptr = (int (*)(int))dlsym(handle, "my_function");
Run Code Online (Sandbox Code Playgroud)