C 中是否有通用函数指针这样的东西可以 assigned/cast 到更严格的原型?

Is there such a thing as a generic function pointer in C that can be assigned/cast to a more restrictive prototype?

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

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

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

int (*functionA)(int)
char (*functionB)(char,int)

是否可以做类似(伪...)的事情

void* functionList(...)[2] = {functionA, functionB};

一起
char FuncNameA[] = "functionA";
char FuncNameB[] = "functionB";
char *functionNames[2] = {FuncNameA, FuncNameB};

为了循环调用 dlsym 进行符号解析

int i = 0;
for(; i<2; i++)
    functionList[i] = dlsym(DL_OPEN_HANDLE, functionNames[i]);

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

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

void *functionList[2];

...

int (*functionA)(int) = (int(*)(int))functionList[0];
char (*functionB)(char,int) = (char(*)(char, int))functionList[1];

C 标准保证任何对象指针类型都可以转换为 void* 并再次转换回来而不会丢失信息(这意味着重新转换的指针将与原始指针比较)。

函数指针有不同的保证:任何函数指针都可以转换为任何其他函数指针类型并再次转换回来而不会丢失信息。

(无法保证函数指针和对象指针之间的转换,或者更具体地说是函数指针和 void* 之间的转换。例如,实现可以使 void* 64 位和函数指针128 位。)

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

typedef void (*funcptr)(void);

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

另一方面,您正在使用 dlsym(),其中 returns 和 void*。我的理解是 POSIX 保证 dlsym() 返回的 void* (如果 name 参数命名一个函数)可以转换为函数指针,可以用来调用函数。如果你关心的只有个函数是dlsym()返回地址的函数,那么你可以使用void*.

(POSIX 之前保证,作为 C 标准的扩展,函数指针可以转换为 void* 并再次返回。该保证后来被删除。感谢 Jonathan Leffler指出这一点。)

无论如何,使用函数指针来存储函数的地址可能会使代码更清晰。

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

Implementations supporting the XSI extension [...] require that an object of type void * can hold a pointer to a function. The result of converting a pointer to a function into a pointer to another data type (except void *) is still undefined, however.

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

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

int (*fptr)(int);
*(void **)(&fptr) = dlsym(handle, "my_function");

当前版本推荐改为:

int (*fptr)(int);
fptr = (int (*)(int))dlsym(handle, "my_function");