inline, weak symbol以及其他

首先,如果某个test.h里有如下内容:

class A {
public:
	int x();
}
 
int A::x()
{
}

那如果只有一个test.cpp引用了它:

#include "test.h"
 
int main()
{
	A a;
	a.x();
}

那还好。但如果还有一个test2.cpp引用了它:

#include "test.h"
 
int foo()
{
	A a;
	a.x();
}

然后把test.cpp和test2.cpp分别编译成.o,再链接,就会报错:

> g++ test.o test2.o -o test
test2.o(.text+0x0): In function `A::x()':
: multiple definition of `A::x()'
test.o(.text+0x0): first defined here

因为两个里面都有A::x()这个symbol嘛,很正常。

这个时候,你会想到,如果inline了,不就好了么!

class A {
public:
	int x();
}
 
inline int A::x()
{
}

恩,的确这样就没有问题了,因为A::x()被inline了。你看test.o的符号表,也找不到这个东西。

但是有时候你会有一些ws的想法。你想,如果A::x()太复杂,inline不了,那编译器不就sb了么!

于是你尝试把A::x()改成bt一些的东西:

class A {
public:
	int x(int no);
};
 
inline int A::x(int no)
{
	if (no == 1)
		return 1;
	else if (no == 2)
		return 1;
	else 
		return x(no-1) + x(no-2);
}

嘛,就是算Fib数列么,但是有这种递归了,你丫就不好inline了吧。

试一试,诶,test.o的符号表里果然出现了A::x():

00000000 W _ZN1A1xEi

或者来c++filt一下

00000000 W A::x(int)

test2.o里也有了这个东西。

但是链接却成功了!而且工作得也挺正常。为了保证靠谱,我们让这俩东西有依赖:
修改test.cpp

#include "test.h"
 
extern void foo();
 
int main()
{
	A a;
	a.x(10);
	foo();
}

试一试,诶,还是可以的!

那就是说,inline虽然实际上没成功,但是程序员看起来还是成功了的。秘密应该就在那个符号里:
可以注意到符号名前面有个W,也就是说,这是个weak symbol…

俩weak symbol碰一起,既然名字一样,那就合并了吧……
如果没有inline呢?看看老的.o:

00000000 T A::x(int)

这就是一普通的symbol。俩这种symbol碰一起,就算multiple def,俩weak碰一起,就不算……

那既然要合并,应该要内容一样才能合并吧?难道编译器比较了内容?不可能吧……
于是,我们就会有更加ws的想法:万一不一样呢?

再搞一个test2.h,基本和test.h一样,但是A::x()实现有点不同:

class A {
public:
	int x(int no);
};
 
inline int A::x(int no)
{
	if (no == 1)
		return 1;
	else if (no == 2)
		return 2;
	else 
		return x(no-1) + x(no-2);
}

嘛,虽然很难看出来,但是这个数列往后移了一位……

改改test2.cpp,让他引用test2.h。随后分别把test.cpp和test2.cpp编译成.o。看这俩.o,他们的A::x()符号看上去一模一样……
链接一把,嘿,还能成……

随后就会好奇么,到底是啥情况?各自用各自的?调某一个的?如果是某一个,哪个?
把结果打出来看看么:
改test.cpp:

#include "test.h"
#include <iostream>
using namespace std;
 
extern void foo();
 
int main()
{
	A a;
	cout << "test ret: " << a.x(10) << endl;
	foo();
}

和test2.cpp:

#include "test2.h"
#include <iostream>
using namespace std;
 
int foo()
{
	A a;
	cout << "test2 ret: " << a.x(10) << endl;
}

分别编译成.o,链接,一点问题都没有…… 结果呢:

test ret: 55
test2 ret: 55

还真合并了,还调到同一个上去了…… 这里其实已经出bug了:既然我inline了,那我应该用的是自己引用的那个.h,也就是说,应该是不同的……
刚才是用

 g++ test.o test2.o -o test

链接的。如果换个顺序呢?

 g++ test2.o test.o -o test

结果是:

test ret: 89
test2 ret: 89

变了…… 看来对于俩weak symbol,先看见的会被采用…… 这个55就是test.h里那个的结果,89是test2.h里那个的……

那如果一个weak一个普通呢?我们把test.h里的inline删了,再试试看。
这次,不管啥顺序,结果都是55了,也就是说,普通symbol比起weak symbol,有决定性的优势……

本文写到这里就差不多了。反正对于这个事情,还是把类实现放.cpp里好……
或许你觉得冲突概率很小。但是如果不是C++而是C呢?万一你恰好和另一个库的函数重名了呢?万一有一个还是inline呢?
所以还是大家都C++并且用名字空间的好……

嘛,其实这个问题基本上是不会出现的,虽说用来考C++啥的,倒是有可能…… 但是这个是标准规定的现象还是编译器自己搞的事情,还有待研究……

华盛顿游记之第二天

今天成果有两个:国家艺术博物馆,和国家航空航天博物馆。

由于昨晚太晚。。。 十二点才出门。
本来想先去航空航天博物馆,路过艺术博物馆就打算先进去看看。
里面有各国各个时期的艺术品,大多数是画作,也有不少雕塑作品。
作为四个工科男。。。 其实大家都缺乏艺术细胞。。。
不过好多展品还是很漂亮的,有些一看上去就很有感觉。。。
看到了毕加索,莫奈等人的画作,想起了美术教科书里的那些画。。。 现在是不是比那个时候有更好的理解了呢。。。
有些写实画比照相机更有现场感。。。 甚至于都能有立体感。
抽象的倒是不多,多数都是写实,好多人物画,以及风景画。以天主教相关内容为题材的很多。
在那里还和郑泽宇同学碰了面,挺和善的一人,好象很好交流。他在cmu读书,好象也是第一年。

之后按原计划去了航空航天博物馆。
先逛了航空部分。有好多个展馆,我们也没按啥次序,随便逛。
各个地方都放着实际飞机一样的模型,各个时代的都有。天上也吊了很多。
有一个是舰载机展厅,装饰得像航母一样。里面有讲飞机起飞着陆过程,塔台控制,飞行员训练等。
也有讲飞机引擎的,各种样子的引擎,v型,星型,等等。另一个馆讲了喷气式飞机的引擎,看上去就是好多片叶片,每片由好多小叶片构成,越来越松。。。
有把实物引擎剖开来给你看的模型,看得很爽。
随后逛了航天馆。有好多缩小火箭模型立在地上,也有真实大小的v2在地上立着。还有登月仓模型,各种人造卫星模型等。
观察了模型的感想是,宇航员还真挤。。。 那么小一个空间。。。
也有介绍太阳系基础知识的部分,话说已经都更新八大行星了。。。
有个地方是展示空间站内部的,居然在展柜里发现了扔进去的某某功的宣传资料。。。 怎么弄进去的。。。
还有个展厅专门介绍空间站,还有个多人参与的知识问答。。。 我们上去乱答一通,居然我还是答对最多的。。。
本来我们打算去玩玩模拟器,结果过去一看,7刀,于是人们都纷纷放弃了这个念头。。。
有个展厅介绍各种基本物理学知识,例如升力产生原因,气压差,空气阻力等。里面有好多可交互的展台,同学们都玩得很开心。

晚饭和郑泽宇同学一起在唐人街中餐馆吃的,还不错。在这里吃了两顿麦当劳终于吃了正常的。。。

夜里依旧是有人dota有人动画…… 本来说要早睡,但是由于一直没打赢电脑,结果又搞到了夜里三四点……

华盛顿游记之第一天

image

image

image

image

image

image

今儿从纽约到了华盛顿。。。
火车好贵,不过有电有网,大致上比汽车贵一倍。
原来这里普通火车就是开180的啊。
出了车站五分钟,就是农村样子了。。。
路过费城等地,也没啥特别的风景。。。

到了华盛顿再换地铁,出了地铁一会就等到了同学。几个月不见,假叔大黄yaoyao还是老样子啊。
夜里在附近晃了一圈,远远看了白宫和方尖碑,之后夜游了林肯纪念堂。。。 林肯很有气势地坐在那里。。。
貌似路过了不少建筑,不过都不认识。。。

之后走了很久到宾馆,房间还不错,就是很小。。。
夜里他们提出打dota,于是就成了三个人打电脑,剩下一个人看动画的情况了。。。
为什么会变成这样。。。

GeManX ver 67

修正了一个sx的bug……

这段时间用GeManX,有时会崩溃…… 而且都是按p向下看贴的时候,而且崩溃之前多半出了输入法的候选词窗口……

然后我就怀疑我写的显示预编辑内容的部分出问题了…… 开了个gdb启gemanx

结果一直开着输入法按p还真挂了…… 一看就是光标移到了窗口外面了……

但是我记得我写了检查的,到了最后一行之外会移回来……

结果一看代码,写的是:

if (row == m_pTermData->m_ColsPerPage)

太弱智了…… 改成

if (row == m_pTermData->m_RowsPerPage)

就好了……

sx的typo……

纪念乔布斯

于是老乔突然就这么走了。

虽说之前也知道他身体不好,但是这个消息还是太突然了。

我也不是果粉,我有的苹果设备也只有表哥送的一个iPod,但是这不妨碍对乔布斯的尊敬。老乔是搞计算机的人们心中的一个符号,是那个波澜壮阔的时代中不可或缺的一部分。他的去世终于使得我们对那个时代的远去有了切实的感觉。

他代表了那种追求完美的精神,那种作出完美的划时代产品的精神。

愿乔布斯安息。