看板 C_and_CPP 關於我們 聯絡資訊
我遇到一個奇怪的問題, 就是當我在 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
tinlans:先不管 ar,你怎麼確定 std::cout 比 Foo:n 先初始化? 10/30 02:12
yoco315:有道理耶.. 這下更窘困了.... 10/30 02:13
yoco315:那,先不管ar,googletest會顯示測試結果,告訴我們有幾個 10/30 02:15
yoco315:test case 被執行,幾個成功幾個失敗.. 10/30 02:15
yoco315:但是顯示出來的結果都是 0 個,代表根本沒有東西被執行.. 10/30 02:16
yoco315:喔,還有可能是因為main在ar之前初始,導致testcaes沒註冊 10/30 02:18
yoco315:阿 該不會真的是「靜態成員初始化順序」這個洞吧.. 10/30 02:19
tinlans:我跟 googletest 不熟所以不知道,但要測試 ar 會不會略過 10/30 02:22
tinlans:初始化應該有更直接的方法,像是在 main 直接 cout 值。 10/30 02:22
BDFishX:剛我試過,只要存取到Foo::n,就會呼叫f(),沒用到就略過 10/30 02:26
tinlans:那是理所當然的,linker 有義務去除不必要的 symbol。 10/30 02:32
tinlans:實測也是跟樓上一樣,用 ar 封裝成 .a 有用到必會初始化。 10/30 02:35
tinlans:只是 cout 的位置是在 main() 裡。 10/30 02:35
tinlans:gdb 也攔得到 foo(),確定有進去。 10/30 02:36
yoco315:那我還是有問題,linker會去除不必要的symbol.. 10/30 02:50
yoco315:那為什麼我直接 link foo.o 的時候還是會初始化 @@? 10/30 02:50
tinlans:看你的主程式內容而定吧,我是覺得都有初始化到才對,只是 10/30 14:22
tinlans:cout 初始化順序不一樣造成你印不出來,用 gdb 攔來看最快 10/30 14:22
tinlans:,如果沒 f 這個 symbol 那 gdb 應該直接跟你說不存在。 10/30 14:22
tinlans:用 nm 直接查也行。 10/30 14:23
BDFishX:在沒有存取到Foo::n的情況下,如果我用gdb去對f設break 10/30 15:42
BDFishX:用foo.a會發生gdb找不到f,foo.o則gdb可以找的到f 10/30 15:42
BDFishX:很明顯g++對foo.a和foo.o的結果是不太一樣的 10/30 15:42
BDFishX:我也對這很好奇為什麼會有這樣的差別~~~@@ 10/30 15:42
yoco315:我把cout改成開一個檔案來寫,結果.a的時候那個檔案沒出來 10/30 20:58
yoco315:所以很肯定是沒有初始化 O_O 不是順序的問題,真的好神奇 10/30 20:58
yoco315:其實也沒什麼,只是這樣我gtest就不能包在ar裡面用.. :D 10/30 20:58
yoco315:確定狀況會是怎樣就好了 O_O.. 沒差.. 10/30 20:59