作者yoco315 (眠月)
看板C_and_CPP
标题[问题] ar 导致 static member 没有初始化...?
时间Fri Oct 30 02:03:08 2009
我遇到一个奇怪的问题,
就是当我在 linux 使用 ar 把 .o 包成 .a 的时候,
被 ar 包装过的 class 所包含的 static data member 不会初始化……
比方说我有一个档案 foo.cpp 是这样
┌────────────────────────────────────┐
|int f() { │
| std::cout << "f()" << std::endl ; │
| return 17 ; │
|} │
| │
|class Foo { │
| static int n ; │
|} │
| │
|int Foo::n = f() ; /* 初始化 static member */ │
└────────────────────────────────────┘
经过下面的 build 步骤……
g++ -c foo.cpp -o
foo.o
ar -cr
foo.a foo.o
g++ main.cc
foo.a
执行 a.out 之後,并没有印出
"f()"。
但是如果我直接使用 foo.o,
那麽就会正常的印出
"f()"。
比方说这样……
g++ -c foo.cpp -o
foo.o
g++ test.cc
foo.o
我好困惑喔。
会有这个问题是因为我在使用 google test 的时候,
发现如果我的 test case 被 ar 包过以後,测试的时候会没有测到那些项目,
google test 写 test case 的时候,其实是透过 macro 把 test case 转成 class。
而 test 的 code 被呼叫的时机,
实际上是这个 class 某一个 static member 初始化的时候会呼叫一个函数,
就像我上面的码一样,於是我怀疑 ar 会让 static member 的初始化被跳过,
後来发现果然是这样...
虽然说这个 class 只有在这个档案里面存在,
所以如果没被用到的话,被略过好像也没差。
但是为什麽 ar 之後就会略过呢?
直接拿 .o 来 link 又为什麽就不会被略过?
囧困,请前辈开示。
OS: 小红帽
Compiler: gcc 3.3
--
To iterate is human, to recurse, divine.
递回只应天上有, 凡人该当用回圈. L. Peter Deutsch
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 118.160.114.40
1F:→ tinlans:先不管 ar,你怎麽确定 std::cout 比 Foo:n 先初始化? 10/30 02:12
2F:→ yoco315:有道理耶.. 这下更窘困了.... 10/30 02:13
3F:→ yoco315:那,先不管ar,googletest会显示测试结果,告诉我们有几个 10/30 02:15
4F:→ yoco315:test case 被执行,几个成功几个失败.. 10/30 02:15
5F:→ yoco315:但是显示出来的结果都是 0 个,代表根本没有东西被执行.. 10/30 02:16
6F:→ yoco315:喔,还有可能是因为main在ar之前初始,导致testcaes没注册 10/30 02:18
7F:→ yoco315:阿 该不会真的是「静态成员初始化顺序」这个洞吧.. 10/30 02:19
8F:→ tinlans:我跟 googletest 不熟所以不知道,但要测试 ar 会不会略过 10/30 02:22
9F:→ tinlans:初始化应该有更直接的方法,像是在 main 直接 cout 值。 10/30 02:22
10F:推 BDFishX:刚我试过,只要存取到Foo::n,就会呼叫f(),没用到就略过 10/30 02:26
11F:→ tinlans:那是理所当然的,linker 有义务去除不必要的 symbol。 10/30 02:32
12F:→ tinlans:实测也是跟楼上一样,用 ar 封装成 .a 有用到必会初始化。 10/30 02:35
13F:→ tinlans:只是 cout 的位置是在 main() 里。 10/30 02:35
14F:→ tinlans:gdb 也拦得到 foo(),确定有进去。 10/30 02:36
15F:→ yoco315:那我还是有问题,linker会去除不必要的symbol.. 10/30 02:50
16F:→ yoco315:那为什麽我直接 link foo.o 的时候还是会初始化 @@? 10/30 02:50
17F:→ tinlans:看你的主程式内容而定吧,我是觉得都有初始化到才对,只是 10/30 14:22
18F:→ tinlans:cout 初始化顺序不一样造成你印不出来,用 gdb 拦来看最快 10/30 14:22
19F:→ tinlans:,如果没 f 这个 symbol 那 gdb 应该直接跟你说不存在。 10/30 14:22
20F:→ tinlans:用 nm 直接查也行。 10/30 14:23
21F:→ BDFishX:在没有存取到Foo::n的情况下,如果我用gdb去对f设break 10/30 15:42
22F:→ BDFishX:用foo.a会发生gdb找不到f,foo.o则gdb可以找的到f 10/30 15:42
23F:→ BDFishX:很明显g++对foo.a和foo.o的结果是不太一样的 10/30 15:42
24F:→ BDFishX:我也对这很好奇为什麽会有这样的差别~~~@@ 10/30 15:42
25F:→ yoco315:我把cout改成开一个档案来写,结果.a的时候那个档案没出来 10/30 20:58
26F:→ yoco315:所以很肯定是没有初始化 O_O 不是顺序的问题,真的好神奇 10/30 20:58
27F:→ yoco315:其实也没什麽,只是这样我gtest就不能包在ar里面用.. :D 10/30 20:58
28F:→ yoco315:确定状况会是怎样就好了 O_O.. 没差.. 10/30 20:59