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