由一个链接错误想到的

原创 2012年03月22日 22:13:48


假设有两个模块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的符号表更新了。然后再链接,就没有问题。


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

NYOJ 52-无聊的小明【模拟】

这天小明十分无聊,没有事做,但不甘于无聊的小明聪明的想到一个解决无聊的办法,因为他突然对数的正整数次幂产生了兴趣。   众所周知,2的正整数次幂最后一位数总是不断的在重复2,4,8,6,2,4,8,6...
  • qq_29600137
  • qq_29600137
  • 2016年04月09日 09:07
  • 299

列举你能想到的UNIX信号,并说明信号用途

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。  UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就...
  • u014649204
  • u014649204
  • 2014年04月19日 14:08
  • 743

由一个单例所想到的

引言 最近关注了公众号“每日一题”,闲来看看,受益匪浅。机缘巧合,在CSDN找到作者的博客——工匠若水。其博文皆是精品,能将一个技术点讲解得全面透彻,本小虾米常常茅塞顿开,故记之。 一个“单例...
  • hailuoli
  • hailuoli
  • 2017年12月18日 10:55
  • 14

由一个例题想到

话说php学深了会用到C的扩展,所以最近一直在看C的书,一来为以后打基础,二来C也是各种语言的基础。 第一遍看完the C programming language后 做一个知识总结,另外第...
  • dj_may
  • dj_may
  • 2013年01月02日 22:40
  • 202

由一个小库存软件想到的

前几天,一个朋友介绍,帮人做一个库存软件。朋友描述的挺简单。就是简单的进货,出货。及报表打印。当然,这只是从客户的角度来描述问题。实现起来就不是那么简单的事了。当时我就答应了,一来因为朋友关系,再者也...
  • diligentcat
  • diligentcat
  • 2015年02月23日 19:31
  • 762

由一个梦想到的

昨天晚上做了一个很神奇的梦,梦里我在清华听一个报告,旁边坐的是一个同学的导师。听完报告,旁边的教授问我,听懂了吗?我说,大概都听懂了,我真的以为我听懂了。于是教授向我抛出了三个问题:是什么?为什么?怎...
  • Andrewseu
  • Andrewseu
  • 2015年08月01日 11:06
  • 579

线性回归、梯度下降(Linear Regression、Gradient Descent)

线性回归、梯度下降(Linear Regression、Gradient Descent) 转载请注明出自BYRans博客:http://www.cnblogs.com/BYRans/   实...
  • qq826364410
  • qq826364410
  • 2017年10月26日 11:48
  • 92

列举你能想到的UNIX信号,并说明信号用途

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。 UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就是Ctr...
  • u013474436
  • u013474436
  • 2016年02月16日 18:36
  • 817

由一个第三类依赖注入想到

无聊的代码: //job用户在库中获取数据形成 public void jobInc(Job job) { .... job.inc(); .... ...
  • wfeng007
  • wfeng007
  • 2013年06月11日 10:30
  • 492

想到一个普及电动汽车的方法

昨晚正在看汽车构造原理的时候,忽然想到电动汽车,电动汽车不用四冲程的内燃机,而是电动机。现在的电动汽车操作方法还是跟内燃机汽车方法一样。 电动汽车的技术已经比较成熟,但是没法普及,因为充电太难,充一...
  • sinox2010p1
  • sinox2010p1
  • 2016年12月02日 15:02
  • 387
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:由一个链接错误想到的
举报原因:
原因补充:

(最多只允许输入30个字)