以下两个是相同的,但C99标准将void *
的转换留给未定义的函数指针。
有人可以解释第二个是如何工作的吗?它有点混乱!
int (*fptr)(int);
fptr = (int (*)(int))dlsym(handle, "my_function");
int (*fptr)(int);
*(void **) (&fptr) = dlsym(handle, "my_function");
答案 0 :(得分:3)
在第一行(第二个代码粘贴)声明一个函数指针(我想你知道)。
现在,dlsym(3)
是一个返回void *
。
所以第二行也可以读作:
*((void **) (&fptr)) = dlsym(handle, "function");
否则说:而不是将函数结果转换为int (*)(int)
,并将给定结果影响到fptr;它在fptr上投射指针(或者它将fptr的地址:指针上的指针转换为void**
)。然后它取消引用这个指针,有效地给出fptr(与原始的相同,但没有int (*)(int)
类型),然后得到dlsym
调用的结果。这只是一种“欺骗”编译器不会触发类型不匹配的警告/错误的方法。还请注意,即使您选择的语法是一种品味问题,在您发布的任何程序中使用它之前,您应该完全理解它。
我希望它有所帮助;)
答案 1 :(得分:2)
与以下之间的区别相同:
float f = 3.14;
int i = (int)f;
和
float f = 3.14;
int i = *(int*)&f;
第一个是值的常规转换,在某些情况下(int< - > float,或者在指针< - > far指针附近的8086天内返回)会导致一些转换;在某些情况下(函数指针和常规指针之间的某些转换)甚至不能编译。
第二个是原始按位复制,编译器将始终接受该复制,但绕过任何转换,并可能导致将变量写入另一个不同大小的变量。可能非常危险,尤其是函数指针。
答案 2 :(得分:1)
第二个版本合法的原因在ISO标准的以下部分:
6.3.2.3指针1指向void的指针可以转换为指向任何对象类型的指针。指向任何对象类型的指针可能是 转换为指向void并再次返回的指针;结果应该 比较等于原始指针。
(**void)
,以及&fptr
是指向对象的指针(因为& fptr是指向函数的指针的指针),所以你的第二个演员阵容表达式由上面的语句明确允许。您的第一个表达式是尝试将指向对象的指针(而不是指向void
的指针,这是标准中的特殊情况)转换为指向函数的指针(不对象) ),正如您所指出的那样,标准不允许这样做。