我只是有一个关于多个弱符号的潜在问题的问题,这个问题来自我的教科书:
一个模块A:
int x;
int y;
p1() {...}
另一个模块B:
double x;
p2() {...}
我的课本说 '在p2中写入x可能会覆盖y' 我可以有点教科书的想法(双倍x是int x大小的两倍,并且int y紧接在int x后面放置int,这是问题所在),但仍然遗漏了细节,我知道何时有多个弱点符号,链接器将随机选择一个,所以我的问题是,链接器选择的模块的哪个x将导致写入p2中的x会覆盖y。
这是我的理解:如果链接器选择模块A的 int x ,将导致结果,因为那样,x,y都是4个字节,而p2(编译后的图像在那里是一个汇编代码movq
与p1中的movl
比较)将更改8个字节,因此覆盖y。
但是我的讲师说,如果仅链接程序选择模块B的 double x ,这将导致覆盖y,这是怎么回事,我是正确的还是我的讲师是正确的?
答案 0 :(得分:0)
根据ISO C,程序将调用未定义的行为。所使用的外部名称必须在程序中的某个位置完全具有一个定义。 *
“弱符号”是某些动态库系统(例如GNU / Linux上的ELF)的概念。该术语在这里不适用。允许对外部符号进行多个定义的链接器据说正在实现“松弛的ref / def”模型。该术语来自ANSI C rationale的6.1.2.2节。
如果我们将宽松的ref / def模型视为文档化的语言扩展,则名称的多个定义将成为本地定义的行为。但是,如果输入不一致,该怎么办?这种情况类似于不良的类型别名的理由几乎可以肯定地未定义。如果一个模块具有int x; int y;
,而另一个模块具有double x
,则通过double x
别名进行的写操作将破坏y
。这不是您可以依赖的东西。这是故意获得锯齿效果的非常差的方法。您想在两个结构之间使用union
或类似的结构。
现在有关“弱符号”的问题:那些是共享库中的外部名称,可以用替代定义覆盖。例如,GNU / Linux系统上GNU C库中的大多数功能都是弱符号。例如,程序可以定义自己的read
函数来替换POSIX函数。无论如何重新定义read
,库本身都不会中断;当需要调用read
时,它不使用弱符号read
,而是使用一些内部别名,例如__libc_read
。
这个机制很重要;它允许库符合ISOC。允许严格符合ISO C的程序使用read
作为外部名称。
*在ISO C99标准中,这是在 6.9外部定义中给出的:“如果在表达式中使用了用外部链接声明的标识符(不是作为操作数的一部分)一个sizeof运算符,其结果是一个整数常量),在整个程序中的某个位置,标识符应恰好是一个外部定义;否则,标识符应不超过一个。”