首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

c/c++中静态链接过程中对未被代码引述的符号的检查

2012-10-27 
c/c++中静态链接过程中对未被代码引用的符号的检查看到一个应该关注的知识点。之前看到的一个帖子:http://m

c/c++中静态链接过程中对未被代码引用的符号的检查
看到一个应该关注的知识点。
之前看到的一个帖子:
http://my.unix-center.net/~Simon_fu/?p=263
大致情况讲的都比较清楚了

a.h:/*******************************************/#include <string> using namespace std; class A { public:     A(void);     A(const char *s);     ~A(void); private:     string name; };/**********************************************/a.cpp:/**********************************************/#include "a.h" #include <iostream> using namespace std; A::A(void) {     cout<< "A construct!\n"; } A::A(const char *s) {     name = string(s);     cout<< "A " + name + " construct!\n"; } A::~A(void) {} static A g_a("globalA");/************************************************/

假设上述代码编译成一个静态库lib.a,该静态库中声明了一个全局变量,预期加载该静态库的时候该全局变量会被创建。
另外创建一个测试的工程来加载这个静态库:

test_staticlib.cpp:/*************************************************/#include <stdio.h> #include "../static_lib/a.h" int main() {     //A a;     //A aa("Local A");     getchar(); }


这个代码在输出时是不会创建全局变量g_a,这个很好理解,因为虽然test_staticlib.cpp include了a.h,但是代码链接时并没发现需要链接a.h中声明的符号,因此实际不会链接那个静态库。
当代码为:
int main() {     A a;     //A aa("Local A");     getchar(); }

则可以发现静态变量g_a会被创建,这里应该思考一下,为何在声明"A a;"之后,静态变量g_a会被创建,而之前的代码却不会?
原因在于代码test_staticlib.cpp引入了A a,这导静态链接时致链接程序需要在参数路径下的目标文件或者lib中找到A的代码块进行链接,当在发现A定义位于lib.a之中时,它会同时将lib.a中所有定义的符号找到对应的代码块。
所以第一段代码虽然include了a.h,但实际没有出现过g_a的符号,所以即使include了,也不会创建变量g_a。
而第二段代码由于引入了符号a需要链接lib.a中定义的对象A的代码块,导致了链接器对lib.a中所有符号的链接检查,发现还存在静态全局变量g_a,于是将g_a也静态链接(拷贝)到执行文件当中。注意这里的“所有”,即使是那些main根本没有引用到的符号,链接程序也会一一查清楚这些符号是否有对应的模块代码存在。
举个例子就比较清楚了:

a.h:/*******************************************/#include <string> using namespace std; class A { public:     A(void);     A(const char *s);    ~A(void); private:     string name; };extern int k;                            <-------------------------------------void fn();                                 <-------------------------------------/**********************************************/a.cpp:/**********************************************/#include "a.h" #include <iostream> using namespace std; A::A(void) {     cout<< "A construct!\n"; } A::A(const char *s) {     name = string(s);     cout<< "A " + name + " construct!\n"; } A::~A(void) {} static A g_a("globalA");void fn(){k++;}                              <-------------------------------------/************************************************/

生成静态库的代码添加箭头部分代码。
该静态库可以成功生成,因为k是作为外部定义的变量,其符号不会在链接器生成lib时去找对应的定义k的代码块链接。
但此时再重新编译链接test_staticlib.cpp会发现会报k缺少引用的错误:
undefined reference to `k'
可以看到尽管test_staticlib.cpp的main函数代码中完全没使用到fn(),但由于对lib.a的链接不仅仅链接了A代码模块,也顺带查找了fn中k符号的链接位置,导致编译器报错。
所以这牵扯到一个问题:如果你的代码中的符号需要链接lib.a中的某段代码,那么你也要同时确定这个lib.a中所有出现的其他符号能顺利找到对应的链接代码块,这种确定性检查会级联到所有和它直接或间接关联的库。

原作者的文章说gcc和ms的链接策略不一样,他在gcc中即使main中没有a.cpp中定义的符号,只包含a.h也能创建g_a,但在我机器上mingw4.5.2上gcc和vs表现是一样的。

static A g_a("globalA")这个定义只在lib.a中存在,因此如果main函数没任何符号会需要跨模块访问其他obj或者lib文件,是没有道理去查看lib.a,并且能意识到应该链接static A g_a("globalA")的符号定义的。


热点排行