4

以下两个是相同的,但 C99 标准将转换 fromvoid *为未定义的函数指针。

有人可以解释第二个是如何工作的吗?它有点混乱!

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


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

3 回答 3

3

在第一行(第二个代码粘贴)声明了一个函数指针(我想你知道这一点)。

现在,dlsym(3)是一个返回 a 的调用void *

所以第二行也可以读作:

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

否则说:而不是将函数结果转换为int (*)(int),并将给定结果影响到 fptr;它将 fptr 上的指针(或将 fptr 的地址:指针上的指针)转换为void**. 然后它取消引用这个指针,有效地给出 fptr(与原始指针相同,但没有int (*)(int)类型),然后得到dlsym调用的结果。这只是一种“欺骗”编译器使其不触发关于类型不匹配的警告/错误的方法。还请注意,即使您选择的语法只是个人喜好问题,在您发布的任何程序中使用它之前,您都应该完全理解它。

我希望它有帮助;)

于 2013-08-19T15:34:42.807 回答
2

区别与以下之间的区别相同:

float f = 3.14;
int i = (int)f;

float f = 3.14;
int i = *(int*)&f;

第一个是值的常规转换,在某些情况下(int <--> float,或返回 8086 天的近指针 <--> 远指针)会导致一些转换;在某些情况下(函数指针和常规指针之间的一些转换)甚至无法编译。

第二种是原始的按位复制,编译器将始终接受但会绕过任何转换,并可能导致将变量写入另一个不同大小的变量。可能非常危险,尤其是函数指针。

于 2013-08-19T15:44:06.250 回答
1

第二个版本合法的原因在于 ISO 标准的以下部分:

6.3.2.3 指针 1 指向 void 的指针可以转换为或从指向任何对象类型的指针转​​换。指向任何对象类型的指针都可以转换为指向 void 的指针并再次返回;结果应与原始指针比较。

(**void),以及&fptr指向对象的指针(因为 &fptr 是指向函数指针的指针),因此上面的语句明确允许第二个表达式中的强制转换。您的第一个表达式试图将指向对象的指针(而不是指向void标准中的特殊情况的指针)转换为指向函数的指针(不是对象),正如您所指出的那样,这是标准不允许的出去。

于 2013-08-19T17:14:26.230 回答