由一个链接错误想到的


假设有两个模块A 和B, A有两个文件 libClass.h, libClass.cpp; B有两个文件, libClient.h, libClient.cpp.

代码如下:

libClass.h:

#ifndef __LIBCLASS_H__
#define __LIBCLASS_H__

class MyTest
{
public:
static bool Foo(int a, char c);
};
#endif //ifndef __LIBCLASS_H__

libClass.cpp:

#include "libClass.h"
bool MyTest::Foo(int a, char c)
{
	return false;
}

libClient.h:

#ifndef __LIBCLIENT_H__
#define __LIBCLIENT_H__
class ClientClass
{
public:
void TestFoo(void);
};
#endif//__LIBCLIENT_H__

libClient.cpp:

#include "libClient.h"
#include "libClass.h"

void ClientClass::TestFoo(void)
{
	int a = 10;
	char c = 's';
	MyTest::Foo(a, c);	
}

最后是一个测试程序 test.cpp:

#include "libClient.h"
int main(void)
{
	ClientClass client;
	client.TestFoo();
	return 0;
}

在命令行分别把两个类文件编到两个静态库里面:

g++ -c libClass.cpp

ar rv libClass.a libClass.o

g++ -c libClient.cpp

ar rv libClient.a libClient.o

最后编译测试程序:

g++ test.cpp libClient.a libClass.a

没有问题。


现在,改一下 第一个类的接口:

libClass.h:

#ifndef __LIBCLASS_H__
#define __LIBCLASS_H__

class MyTest
{
public:
static bool Foo(int a, char c, long *p = 0);
};
#endif //ifndef __LIBCLASS_H__

libClass.cpp:

#include "libClass.h"
bool MyTest::Foo(int a, char c, long *p)
{
	return false;
}

重新编译一下:

g++ -c libClass.cpp

ar rv libClass.a libClass.o

然后,编译测试程序:

g++ test.cpp libClient.a libClass.a

libClient.a(libClient.o): In function `ClientClass::TestFoo()':
libClient.cpp:(.text+0x20): undefined reference to `MyTest::Foo(int, char)'
collect2: ld returned 1 exit status


说起来应该不发生错误才对,因为增加的只是一个函数的默认参数,client 代码不用修改。

但是从错误信息来看,另一类生成的目标代码已经记忆了原来的类的接口信息,所以如果不更新另一个类的目标代码,链接惠出错。

我们检查一下 libClient.o 的符号表:

charles@China:/WinD/Code/myTest$ nm -C libClient.o

00000000 T ClientClass::TestFoo()
         U MyTest::Foo(int, char)
         U __gxx_personality_v0

果然,client目标代码里面的函数 Foo()符号还是修改之前的那个。现在这个函数接口参数已经被修改了,所以会发生错误。

现在重新编译 libClient.cpp:

rm libClient.o
cc -c libClient.cpp
ar rv libClient.a libClient.o

然后, 再检查一下符号表:

charles@China:/WinD/Code/myTest$ nm -C libClient.o 
00000000 T ClientClass::TestFoo()
         U MyTest::Foo(int, char, long*)
         U __gxx_personality_v0

现在,  client的符号表更新了。然后再链接,就没有问题。


由此得出一个结论,使用静态链接的时候,如过一个模块的接口(或者全局变量)有变更,除了该模块要重新编译外,其他依赖于这个模块的代码也要重新编译。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值