今天阅读《深度探索C++对象模型》,得知在C之中,未初始化的全局对象“被视为一个‘临时性的定义’,因为它没有明确的初始化操作。一个‘临时性的定义’可以在程序中发生多次,那些实例会被链接器折叠起来,只留下单独一个实体”(见第197页)。于是我做了做实验,以验证书上说的话。
我定义了两个c文件,分别是test1.c:
#include <stdio.h>
int a;
extern void foo();
int main()
{
a = 1;
foo();
printf("%d\n", a);
}
和test2.c:
int a;
void foo()
{
a = 2;
}
我采用Visual Studio C++ 2010的命令行提示符,用c语言模式分别对这两个文件进行编译,再将产生的两个obj文件链接,没有遇到任何错误:
>cl /TC /c test1.c
>cl /TC /c test2.c
>link /out:test.exe test1.obj test2.obj
执行test.exe,输出结果是2,可见test1.c和test2.c中的变量a是同一个实例。
而《深度探索C++对象模型》又提到:“C++并不支持‘临时性的定义’,这是因为class构造行为的隐含应用之故……global在C++中被视为完全定义(它会阻止第二个或更多个定义)……C++的所有全局对象都被当作‘初始化过的数据’来对待。”(还是见第197页)。
因此我将test1.c改名为test1.cpp,将test2.c改名为test2.cpp,用c++模式分别对这两个文件进行编译,再将产生的两个obj文件链接。此时就遇到了链接错误:
>cl /EHsc /c test1.cpp
>cl /EHsc /c test2.cpp
>link /out:test.exe test1.obj test2.obj
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
test2.obj : error LNK2005: "int a" (?a@@3HA) already defined in test1.obj
test.exe : fatal error LNK1169: one or more multiply defined symbols found
看来书中的话果然没错。
不过需要注意的是,这些话只对未初始化的全局对象有效。举个例子,如果在test1.c中将int a;改为int a = 1;,在test2.c中将int a;改为int a = 2;,那么test1.obj和test2.obj的链接也会出现重定义错误。