void f(void);
int x = 15213;
int main()
{
f();
printf("x = %dn", x);
return 0;
}
/* bar3.c */
int x;
void f()
{
x = 15212;
}
在上面的代码中,我得到的输出是 15212。我不明白怎么回事?
首先,主函数调用 f() 在另一个 c 文件中定义。在 f() 中,x 的值从 15213 更改为 15212。然后我们正在打印 x。但是对 x 所做的更改应该只保留在 f 中,对吗?X 的范围应仅限于 f() 。即便如此,它也在打印 15212
您已在 2 个翻译单元中定义了具有外部链接的变量x
。因此,程序的行为是不确定的。C11 6.9p5:
外部定义
- 是一个外部声明,也是函数(内联定义除外)或对象的定义。如果在表达式中使用了用外部链接声明的标识符(而不是作为结果为整数常量的 sizeof 或 _Alignof 运算符的操作数的一部分),则在整个程序中的某个地方,标识符应只有一个外部定义;否则,不得超过一个。
有一个通用的扩展(C11 J.5.11),它存在于POSIX系统(Unix,Mac OSX,Linux)上,导致这些外部变量定义合并为一个:
J.5.11 多个外部定义
- 对象的标识符可能有多个外部定义,无论是否显式使用关键字 extern;如果定义不一致,或者初始化了多个定义,则行为是未定义的 (6.9.2)。
但是,其他平台的 C 编译器不一定需要遵循此规则。
如果您希望两个文件都有名为x
的单独变量,请在每个声明前面加上关键字static
,即static int x;
.如果您希望它们可移植为一个,请仅在一个文件中使用int x;
,在所有其他文件中extern int x;
;此extern
AL 声明可以放入头文件中。
由于x
是在任何函数的作用域之外定义的,因此它具有全局作用域。 因此,运行f()
来分配其值实际上会更改其值,如图所示。
当main()
运行时,它做的第一件事是调用f()
来更改值(有些人可能会认为这是一种副作用)。 这就是为什么从不使用初始化值 15213 的原因。