Skip to content

C语言不同文件是否可以声明同名变量

复制本地路径 | 在线编辑

一个挺无聊的问题,我估计平时代码基本不会这样写的。这个是南大袁春风老师计算机系统基础开课提的几个例子中的一个。简单稍微记录一下吧。

一、问题介绍

如下两个文件,是否可以链接,以及链接之后的结果?

main.c

int d = 100;    // 定义 d,类型为 int
int x = 200;

int main() {
    p1();
    printf("d = %d, x = %d\n", d, x);
    return 0;
}

p1.c

double d;       // 定义 d,类型为 double
void p1() {
    d = 1.0;
}

二、解答

1. 编译阶段(单独编译)

  • main.c 中定义了全局变量 d(类型为 int),并使用 p1()
  • p1.c 中定义了全局变量 d(类型为 double),并定义了 p1() 函数。

编译单个文件时,两边都不会出错(编译器允许相同名字的全局变量在不同翻译单元中出现,只要链接时不冲突)。生成:

main.o: 定义符号 d(int 类型)
p1.o:   定义符号 d(double 类型)

2. 链接阶段(Linking)

链接器在将多个目标文件合并时,会把同名的全局符号视为同一个全局标识符
也就是说:

main.o 中的 d  和  p1.o 中的 d
会被当作是同一个变量。

3. 运行阶段

p1() 写入8字节的 double 值 1.0 时,会覆盖掉x变量的内存空间,而 double 值 1.0 的IEEE754 表示为:0x3FF0000000000000,会被解释为两个int值:低32位为0x00000000,高32位为0x3FF00000。

可能的输出结果:

d = 0, x = 1072693248

三、实际行为(不同编译器下)

  • GCC / Clang 会正常链接通过,不报错(但可能有 warning)。
gcc main.c p1.c -o test

链接成功,但:

  • 最终 d 实际上是单个符号;
  • 谁的大小占主导取决于链接器的实现;
  • p1() 修改的可能是 d 的前 8 字节;
  • printf() 访问的是 d 的前 4 字节;
  • 导致 d 的值是未定义的乱数

四、正确写法

如果要在两个文件中共享同一个变量,类型必须一致:

#include <stdio.h>

extern double d;   // 声明同类型
int x = 200;

int main() {
    p1();
    printf("d = %f, x = %d\n", d, x);
    return 0;
}
double d;          // 定义同类型
void p1() {
    d = 1.0;
}

输出:

d = 1.000000, x = 200

Comments