当两个.c文件具有相同符号但不同类型的全局变量时,引用如何工作?

amo*_*luc 6 c linker global-variables

C

说我有以下C模块:

模块1

#include <stdio.h>
int x;
int main(){
  foo();
  printf("%i\n",x);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

模块2

double x;
void foo(){
  x = 3.14;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:链接器在这种情况下做了什么?在我正在阅读的教科书中,它说编译器只为链接器符号表选择两个弱全局变量中的一个.选择这两个中的哪一个?或者都被选中了?如果是这样,为什么?谢谢.

oua*_*uah 5

C表示它是未定义的行为.

(C99,6.9p5)"如果在表达式中使用了使用外部链接声明的标识符(除了作为sizeof运算符的操作数的一部分,其结果是整数常量),整个程序中的某个地方应该只有一个外部标识符的定义;否则,不得超过一个"

未定义的行为意味着链接器可以在存在多个外部对象定义时中止链接过程.

现在链接器很好(或者是邪恶的,你可以选择)并且通常具有默认扩展来处理多个外部对象定义而在某些情况下不会失败.

如果你正在使用gccld从binutils的,如果你的两个对象被明确初始化,你会得到一个错误.例如,您拥有int x = 0;第一个翻译单元和double x = 0.0;.

否则,如果未明确初始化其中一个外部对象(示例中的情况),gcc则会将两个对象静默组合为一个符号.您仍然可以要求链接器通过传递选项来报告警告--warn-common.

例如,在链接模块时:

gcc -Wl,--warn-common module1.o module2.o

要使链接过程中止,您可以请求链接器使用--fatal-warningsoption(-Wl,--fatal-warnings,--warn-common)将所有警告视为错误.

使链接过程中止的另一种方法是使用-fno-common编译器选项,如@teppic在他的回答中所解释的那样.-fno-common禁止外部对象在编译时获取Common符号类型.如果对两个模块执行此操作然后进行链接,您还将获得多定义链接器错误.

gcc -Wall -fno-common -c module1.c module2.c

gcc module1.o module2.o