在《程序员的自我修养---链接、装载与库》这本书中,较为详细的介绍了编译器底层的一些工作机制。
其中涉及到这样一段代码:
1 #include <stdio.h>
23 namespace myname
4 {
5 int var = 42; //经由GCC编译器的符号修饰后变为 _ZN6myname3varE(供连接器链接使用的符号)
6 }
7
8 extern "C" double _ZN6myname3varE;
9
10 int main()
11 {
12 printf("%d\n",_ZN6myname3varE);
13 return 0;
14 }
编译并运行:
g++ t.c -o a.out
./a.out
得到输出结果:
42
若将第8行注释掉,编译会产生错误:
t.c: In function 'int main()':
t.c:12: error: '_ZN6myname3varE' was not declared in this scope
若将第3-6行注释掉(第8行不注释),编译也会产生错误:
/tmp/cc0asb7n.o: In function `main':
t.c:(.text+0x13): undefined reference to `myname::var'
collect2: ld returned 1 exit status
由此可见,此程序成功运行的关键在于第8行引入了外部变量_ZN6myname3varE,而保证了第12行编译时不会出错,并且12行的_ZN6myname3varE符号不会进行符号修饰(编译时),而是保持不变,而在连接时其意义相当于myname::var,即引用(链接)了namespace命名空间中的变量var。
本质上还是体现了编译系统或者说计算机体系的分层思想,在这段代码中的具体体现就是,通过extern “C”这条语句成功的欺骗了编译器,使第12行成功的通过了编译,为连接器做好了链接准备。
附图(GCC基本C++名称修饰规则):