2017-04-20 50 views
1

dlsym()man page名单对dlsym()的解决方法返回类型

*(void **) (&cosine) = dlsym(handle, "cos"); 

作为用于铸造的dlsym()返回值一种解决方法。

*(void **) (&cosine)这是什么意思?据我所知cosine是一个先前定义的函数指针,但我不知道为什么在名称前需要使用&符号&(错误没有&)。此外,我不知道为什么指针void *void **)再次与*一起使用。

+0

这里假设一个'double(* cosine)(double);'或类似的声明。 – ephemient

+0

非常常见的问题。如果数据指针和代码指针的大小相同,这个“解决方案”完美地工作。否则它会失败壮观。 –

+0

@LorinczyZsigmond你一般都是对的,但是'dlsym'特别来自POSIX,它要求这在合适的实现中起作用。换句话说,POSIX只允许具有平坦内存模型的平台,其中所有指针都是相同的。 – ephemient

回答

2

让我们来解开这一点在一个时间:

&cosine 

这需要一个指针变量cosine,所以这将是一个指向一个函数指针。

(void **) &cosine 

我们将指向函数指针的指针转换为指针指向void的指针。

* (void **) &cosine 

我们取消引用指针铸造,分配的dlsym()到它的结果。

实际上,发生的事情是问题的一个侧面步骤。我们假设cosine是一个void *(通过间接级别)并分配给它,而不是将dlsym()的结果转换为正确类型的函数指针。

+0

没错。 C没有定义数据指针和函数指针之间的转换。定义'void * dlsym(const char *,int)'的POSIX确实意味着可以在'void *'中表示一个函数指针(这是一个在标准C中没有做出的保证),但是它不会'避免将一个'void *'强制转换为函数指针的事实没有明确定义。在这里,'&cosine'是一个数据指针(指向一个函数指针),并且允许通过'void *'投射一个数据指针,所以这使我们保持安全。 – ephemient

+0

非常明确的解释。谢谢! –

+0

@ephemient,你确定它解决了这个问题吗? 'void *'和'double(*)(double)'似乎不是兼容的类型,所以这会违反严格的别名规则,而不是依赖于可以转换为void *的函数指针。违反严格的别名会导致UB,但编译器有真正的机会在不正确的显式转换中发出警告/错误。在我看来,如果编译器允许你这样做,而不是在运行时由于UB而可能中断,那么你最好进行转换并静态检查。 – zneak