*(void**)(&;funcp)在这行涉及dlsym()的代码中做了什么?

*(void**)(&;funcp)在这行涉及dlsym()的代码中做了什么?,c,shared-libraries,C,Shared Libraries,有人能帮我解释这行代码吗 我不明白*(void**)(&funcp)的作用。dlsym()与dlopen()和dlclose()有关,请参见手册页 您看到的这行代码在dlopen()加载的二进制对象中查找符号(获取符号的值,在本例中假定它是函数地址),并将其分配给指针变量funcp 当funcp被类型转换为相应的函数类型(即给定正确的函数签名)时,可以通过funcp调用该函数,并传递参数 dl(动态库)函数集是一种机制,在支持dlopen/dlsym/dlclose的系统上,插件通常是通过这种机

有人能帮我解释这行代码吗

我不明白
*(void**)(&funcp)
的作用。

dlsym()与dlopen()和dlclose()有关,请参见手册页

您看到的这行代码在dlopen()加载的二进制对象中查找符号(获取符号的值,在本例中假定它是函数地址),并将其分配给指针变量funcp

funcp被类型转换为相应的函数类型(即给定正确的函数签名)时,可以通过funcp调用该函数,并传递参数

dl(动态库)函数集是一种机制,在支持dlopen/dlsym/dlclose的系统上,插件通常是通过这种机制实现的。插件必须符合用户或社区定义的界面,希望加载插件的代码也必须知道该界面,以便知道如何按名称查找和定义符号,以及如何转换和使用符号

另一种方式是,它允许您对链接时不可用的对象进行调用,并允许您的代码在运行时执行链接器在链接时为您处理的操作

dlsym()返回一个(void*),因为它不能假设它正在加载的符号的任何内容,可能是变量、函数入口点等。。。要对返回的值执行任何操作,通常需要将其强制转换为与加载了dlopen()的二进制文件中的符号对应的类型。

这可能会澄清它(来自):

更新:我没有包含与snarky完全相同的链接。我错过了原始问题中的链接。:p)

通过将
funcp
中的数据重新解释为
void*
并存储到函数指针中,基本上可以避免将
void*
dlsym()
转换为函数指针。这是通过获取
funcp
的地址(变量本身的地址),假装该地址引用了
void*
(通过
(void**)
cast),取消对它的引用,并将
dlsym()
中的
void*
存储到其中。更简单的形式在实践中也可能奏效

这种通过获取数据的地址、将地址转换为指向不同类型的指针并取消引用来“重新解释”数据的方法通常被称为类型双关。双关语来自相同的数据,当以不同的方式解释时,具有不同的含义,这也是真正的双关语的工作原理

(类型双关在某些情况下可能是不安全的,包括编译器使用严格的别名规则时,该规则允许它假设不同类型的某些指针不使用别名(它们不引用相同的数据)。上面的强制转换可能会违反严格的别名,因为您会得到一个函数指针和一个引用相同数据的
void*
,尽管在这种情况下它“可能在实践中起作用”)


(ISO C不要求函数指针可以安全地转换为
void
指针并返回的原因可能是函数和数据(
void
指针指的是“数据”)在某些计算机上是分开存储的。由于它们是分开的,它们也可能使用不同的地址长度或格式,因此函数指针和数据指针之间的转换可能没有意义。以这种方式分开代码和数据的体系结构称为哈佛体系结构。)

您在哪里找到这一行的?在共享库中使用dlopen API,您的问题不明确。你说请解释一下,你没有说你被哪一部分弄糊涂了。因此,让人们浪费时间更全面地回答你的问题,而不向他们表示一点感激,这是对社区的一种伤害。我认为这是一个好问题。他们这样做的原因,而不仅仅是
funcp=…
,非常微妙。你还知道其他事情吗?因为我不知道您知道什么和不知道什么,也不知道您的问题是否与dlsym()本身有关,或者与返回的值被转换为void*的方式有关,等等。。。所以我试着涵盖所有的基本知识。所以,稍后,不知道dlopen()的人可能会在这个问题上绊倒,然后他们可以了解更多的上下文。如果你喜欢这个问题,尊重人们为帮助你所付出的努力,并找到对你有用的东西,请投票表决,并回报他们。我认为值得一提的是,这个丑陋的黑客正在打破严格的别名规则,更可取的方法是向函数指针强制转换(如你的引用)。@cremno:嗯,是的,也许我也可以在那里严格的别名规则。想知道适当的报道是否会使答案过于杂乱无章@克伦诺:我试过了!
*(void **) (&funcp) = dlsym(libHandle, argv[2]); 
/* The rather clumsy cast above is necessary because the ISO C standard
   does not require that pointers to functions can be cast back and
   forth to 'void *'. (See TLPI pages 863-864.) SUSv3 TC1 and SUSv4
   accept the ISO C requirement and propose casts of the above
   form as the workaround. However, the 2013 Technical Corrigendum
   (TC1) to SUSv4 requires casts of the following more natural form
   to work correctly:

       funcp = (void (*)()) dlsym(libHandle, argv[2]);

   Various current compilers (e.g., gcc with the '-pedantic' flag)
   may still complain about such casts, however. */