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