GCC的Link行为

编译器:G++
OS:LINUX

 

1.link顺序

GCC Link程序在.o文件列表中查找被引用实体(函数或Class)时不设定顺序,即引用实体所在.o文件出现

在被引用实体所在的.o文件的左侧,或右侧都能通过编译,不会出现找不到引用的错误
但若从.a文件列表中搜索被引用实体,情况将不同,总是则从右向左顺序查找,因此,被引用实体所在.a

文件必需出现在引用实体所在.a文件的右侧,否则,将报“未定义引用(undefined reference)”错误

2.重复引用的处理
若同一实体分别在两个以上.o或.a文件中被实现,Link时又同时指定了这些.o或.a文件,结果会怎么样?

你可能认为这是个常识问题:编译器报多重定义的错。事实果真如此吗?正确答案:取决于你编译命令行

怎么写。
若指定.o文件列表,你的常识是对,编译器报多重定义的错(multiple definition)。
但若指定.a文件列表,你的常识将是错的,编译器并不报错,而是引用.a文件列表中,从若向左第一次出

现的实现。
引用实体和被引用实体混合出现在.o, .a的文件中时情况较复杂,大体符合.o优先的原则
引用与被引用实体分别所在的.o被打包成一个.a时,打包时.o没有顺序依赖,但当其中存在多重定义时,

情况将不同,实际被引用的是按照打包顺序,从左向右,出现在引用实体右侧的第一个实现。

测试过程如下:
1.在a.h文件中定义一个函数:
void f_a();

2.在a.cpp中提供一个实现版本
void f_a()
{
   printf("hello f_a from a.cpp/n");
}
编译成a.o, 并ar rsuv a.a a.o成a.a

3.在b.cpp中提供void f_a()并一实现版本
void f_a()
{
  printf("hello f_a from b.cpp/n");
}
编译成b.o, 并ar rsuv b.a b.o成b.a

4.在c.cpp中实现
void f_c()
{
  printf("f_c will call f_a.../n");
  f_a();
}
编译成c.o, 并ar rsuv c.a c.o成c.a

5.在main.cpp中call f_c()
int main(int argc, char **argv)
{
 f_c();
 return 0;
}

6.测试Link顺序
6.1 g++ -o main main.cpp a.o c.o或g++ -o main main.cpp c.o a.o将得到同样的正确的结果--被引

用实体在.o文件列表中无顺序依赖

6.2 g++ -o main main.cpp c.a a.a通过编译,得到正确结果,但g++ -o main main.cpp a.a c.a将通不

过编译,报错:undefined reference to `f_a()' -- 被引用实体在.a文件列表中有顺序依赖,被引用

实体必需出现在引用实体的左侧

7.测试多重实现
7.1 g++ -o main main.cpp a.o b.o c.o(a.o, b.o, c.o任意排列组合),编译将失败,报错:multiple

definition of `f_a()'--在.o列表中若存在多重定义,编译将失败

7.2 g++ -o main main.cpp a.a b.a c.a报错:undefined reference to `f_a()'--符合上面关于Link

顺序的测试; g++ -o main main.cpp c.a b.a a.a,通过编译,实际引用b.a中的实现; g++ -o main

main.cpp c.a a.a b.a, 通过编译,实际引用a.a中的实现。

7.3 g++ -o main main.cpp cc.a a.o b.a, 通过编译,实际引用a.o中的实现版本--.o中的实现被引用

的优先级高于.a;g++ -o main main.cpp c.a b.a a.o, 编译出错,报“多重定义(multiple definition

of `f_a()')”; g++ -o main main.cpp b.a c.a a.o或g++ -o main main.cpp b.a a.o c.a,通过编译,

实际引用a.o中的实现--引用实体与被引用实体有的出现在.a中,有的出现在.o中,且存多重定义的情形

是有些复杂的,实际工作中应谨慎处理

7.4 将多个.o打成一个.a(文件名体现打包顺序),g++ -o main main.cpp ac.a或g++ -o main main.cpp

ca.a, 通过编译; g++ -o main main.cpp cc.o ab.a,编译通过,实际引用a.o实现,g++ -o main

main.cpp cc.o ba.a,编译通过,实际引用b.o实现; g++ -o main main.cpp abc.a,通过编译,实际引用

a.o实现;g++ -o main main.cpp bac.a,通过编译,实际引用b.o实现;g++ -o main main.cpp acb.a,通

过编译,实际引用b.o实现; g++ -o main main.cpp abc.a,通过编译,实际引用a.o实现;g++ -o main

main.cpp bac.a,通过编译,实际引用b.o实现

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值