*(void **) (&funcp) 在这行涉及 dlsym() 的代码中做了什么?
What does *(void **) (&funcp) do in this line of code involving dlsym()?
谁能帮我解释这行代码(来自here)?
*(void **) (&funcp) = dlsym(libHandle, argv[2]);
我不明白 *(void **) (&funcp)
的作用。
dlsym() 与 dlopen() 和 dlclose() 有关,请参阅手册页。
你看到的那一行是在 dlopen() 加载的二进制对象中查找一个符号(获取符号的值,在本例中假定它是一个函数地址),并赋值它指向指针变量funcp。
当 funcp 被类型转换为相应的函数类型时,意味着给定适当的函数签名,该函数可以通过 funcp 调用并传递参数。
dl(动态库)函数集是通常在支持 dlopen/dlsym/dlclose 的系统上促进插件的机制。插件必须符合用户或社区定义的接口,想要加载插件的代码也必须知道该接口,以便知道如何按名称查找和定义符号,以及如何转换和使用它们.
另一种说法是,它允许您调用一个在 link 时间不可用的对象,并让您的代码在运行时执行 linker 为您处理的事情在 link 时间。
dlsym() returns a (void *) 因为它不能对它正在加载的符号做任何假设,它可以是一个变量,一个函数入口点等等...来做任何事情返回的值,一般需要将其转换为与 dlopen() 加载的二进制文件中的符号对应的类型。
这可能会澄清(来自 here):
(更新: 我没有包含完全相同的 link 来刻薄。我错过了 link原始问题。 :P)
/* 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. */
通过将 funcp
中的数据重新解释为 void*
和存储到那个。这是通过获取 funcp
的地址(变量本身的地址),假装该地址引用 void*
(通过 (void**)
转换),取消引用它,并存储void*
从 dlsym()
到它。更简单的形式也可能在实践中起作用。
这种 "reinterpreting" 数据的方法通过获取其地址,将该地址转换为指向不同类型的指针并取消引用,通常被称为 type punning方法。 双关语 来自相同的数据,当以不同的方式解释时具有不同的含义,这也是真正的双关语的工作方式。
(在某些情况下,类型双关可能是不安全的,包括当编译器使用 严格的别名规则 时,它假设某些不同类型的指针不 alias(它们不引用相同的数据)。上面的转换可能会违反严格的别名,因为你得到一个函数指针和一个引用相同数据的 void*
,尽管它是"likely to work in practice" 在这种情况下。)
(ISO C 不要求函数指针可以安全地转换为 void
指针并返回的原因可能是函数和数据(void
指针引用 "data")分别存储在某些机器上。由于它们是分开的,它们也可能使用不同的地址长度或格式,因此函数指针和数据指针之间的转换可能没有意义。以这种方式分离代码和数据的体系结构称为 哈佛架构.)
谁能帮我解释这行代码(来自here)?
*(void **) (&funcp) = dlsym(libHandle, argv[2]);
我不明白 *(void **) (&funcp)
的作用。
dlsym() 与 dlopen() 和 dlclose() 有关,请参阅手册页。
你看到的那一行是在 dlopen() 加载的二进制对象中查找一个符号(获取符号的值,在本例中假定它是一个函数地址),并赋值它指向指针变量funcp。
当 funcp 被类型转换为相应的函数类型时,意味着给定适当的函数签名,该函数可以通过 funcp 调用并传递参数。
dl(动态库)函数集是通常在支持 dlopen/dlsym/dlclose 的系统上促进插件的机制。插件必须符合用户或社区定义的接口,想要加载插件的代码也必须知道该接口,以便知道如何按名称查找和定义符号,以及如何转换和使用它们.
另一种说法是,它允许您调用一个在 link 时间不可用的对象,并让您的代码在运行时执行 linker 为您处理的事情在 link 时间。
dlsym() returns a (void *) 因为它不能对它正在加载的符号做任何假设,它可以是一个变量,一个函数入口点等等...来做任何事情返回的值,一般需要将其转换为与 dlopen() 加载的二进制文件中的符号对应的类型。
这可能会澄清(来自 here):
(更新: 我没有包含完全相同的 link 来刻薄。我错过了 link原始问题。 :P)
/* 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. */
通过将 funcp
中的数据重新解释为 void*
和存储到那个。这是通过获取 funcp
的地址(变量本身的地址),假装该地址引用 void*
(通过 (void**)
转换),取消引用它,并存储void*
从 dlsym()
到它。更简单的形式也可能在实践中起作用。
这种 "reinterpreting" 数据的方法通过获取其地址,将该地址转换为指向不同类型的指针并取消引用,通常被称为 type punning方法。 双关语 来自相同的数据,当以不同的方式解释时具有不同的含义,这也是真正的双关语的工作方式。
(在某些情况下,类型双关可能是不安全的,包括当编译器使用 严格的别名规则 时,它假设某些不同类型的指针不 alias(它们不引用相同的数据)。上面的转换可能会违反严格的别名,因为你得到一个函数指针和一个引用相同数据的 void*
,尽管它是"likely to work in practice" 在这种情况下。)
(ISO C 不要求函数指针可以安全地转换为 void
指针并返回的原因可能是函数和数据(void
指针引用 "data")分别存储在某些机器上。由于它们是分开的,它们也可能使用不同的地址长度或格式,因此函数指针和数据指针之间的转换可能没有意义。以这种方式分离代码和数据的体系结构称为 哈佛架构.)