我的问题:
以下是一个示例。上述问题归结为C是否保证main.c
打印的内容:"Function equality: 1"
或"Function equality: 0"
,在第一种情况下,动态加载器如何实现这一点。
common.h:
extern void * getc_main;
extern void * getc_shared;
void assign_getc_shared();
main.c:
#include <stdio.h>
#include "common.h"
int main()
{
getc_main = (void*) getc;
assign_getc_shared();
printf("Function equality: %d\n", getc_main == getc_shared);
return 0;
}
shared.c:
#include <stdio.h>
#include "common.h"
void assign_getc_shared()
{
getc_shared = (void*) getc;
}
在Unix中,这将使用以下命令进行编译:
cc -shared -fPIC -o libshared.so shared.c
cc -o main main.c -L. -lshared
并执行:
LD_LIBRARY_PATH=. ./main
答案 0 :(得分:13)
2011年(N1570委员会草案)6.5.9 6:“两个指针比较相等,当且仅当......两者都指向相同的......函数.......所以,是的,同一个函数的两个指针比较相等。
当在两个不同的对象模块中获取函数的地址时,编译器将占位符放在目标代码中。当对象模块链接到可执行文件或在运行时与动态库链接时,将填充该占位符。
对于动态库,动态加载器根据需要填充可执行文件中的所有占位符,或者每个函数的地址实际上是跳转到实际函数的某些存根代码的位置,以及该存根中的占位符或由该存根使用代码由动态加载器填充。
此外,请注意,可执行文件可以包含多个函数实例。编译器可能会在几个地方插入函数内联,或者由于其自身的原因,可能包括函数的特化以及通用版本。但是,当执行函数的地址时,编译器必须提供单个通用版本的地址。 (或者编译器必须确保程序的行为就像完成一样。例如,如果编译器可以检测到程序没有比较指针,那么理论上它可以为地址的某些实例使用不同的地址功能。)