[問題] ar 導致 static member 沒有初始化...?

看板C_and_CPP (C/C++)作者 (眠月)時間16年前 (2009/10/30 02:03), 編輯推噓1(1027)
留言28則, 3人參與, 最新討論串1/1
我遇到一個奇怪的問題, 就是當我在 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

10/30 02:12, , 1F
先不管 ar,你怎麼確定 std::cout 比 Foo:n 先初始化?
10/30 02:12, 1F

10/30 02:13, , 2F
有道理耶.. 這下更窘困了....
10/30 02:13, 2F

10/30 02:15, , 3F
那,先不管ar,googletest會顯示測試結果,告訴我們有幾個
10/30 02:15, 3F

10/30 02:15, , 4F
test case 被執行,幾個成功幾個失敗..
10/30 02:15, 4F

10/30 02:16, , 5F
但是顯示出來的結果都是 0 個,代表根本沒有東西被執行..
10/30 02:16, 5F

10/30 02:18, , 6F
喔,還有可能是因為main在ar之前初始,導致testcaes沒註冊
10/30 02:18, 6F

10/30 02:19, , 7F
阿 該不會真的是「靜態成員初始化順序」這個洞吧..
10/30 02:19, 7F

10/30 02:22, , 8F
我跟 googletest 不熟所以不知道,但要測試 ar 會不會略過
10/30 02:22, 8F

10/30 02:22, , 9F
初始化應該有更直接的方法,像是在 main 直接 cout 值。
10/30 02:22, 9F

10/30 02:26, , 10F
剛我試過,只要存取到Foo::n,就會呼叫f(),沒用到就略過
10/30 02:26, 10F

10/30 02:32, , 11F
那是理所當然的,linker 有義務去除不必要的 symbol。
10/30 02:32, 11F

10/30 02:35, , 12F
實測也是跟樓上一樣,用 ar 封裝成 .a 有用到必會初始化。
10/30 02:35, 12F

10/30 02:35, , 13F
只是 cout 的位置是在 main() 裡。
10/30 02:35, 13F

10/30 02:36, , 14F
gdb 也攔得到 foo(),確定有進去。
10/30 02:36, 14F

10/30 02:50, , 15F
那我還是有問題,linker會去除不必要的symbol..
10/30 02:50, 15F

10/30 02:50, , 16F
那為什麼我直接 link foo.o 的時候還是會初始化 @@?
10/30 02:50, 16F

10/30 14:22, , 17F
看你的主程式內容而定吧,我是覺得都有初始化到才對,只是
10/30 14:22, 17F

10/30 14:22, , 18F
cout 初始化順序不一樣造成你印不出來,用 gdb 攔來看最快
10/30 14:22, 18F

10/30 14:22, , 19F
,如果沒 f 這個 symbol 那 gdb 應該直接跟你說不存在。
10/30 14:22, 19F

10/30 14:23, , 20F
用 nm 直接查也行。
10/30 14:23, 20F

10/30 15:42, , 21F
在沒有存取到Foo::n的情況下,如果我用gdb去對f設break
10/30 15:42, 21F

10/30 15:42, , 22F
用foo.a會發生gdb找不到f,foo.o則gdb可以找的到f
10/30 15:42, 22F

10/30 15:42, , 23F
很明顯g++對foo.a和foo.o的結果是不太一樣的
10/30 15:42, 23F

10/30 15:42, , 24F
我也對這很好奇為什麼會有這樣的差別~~~@@
10/30 15:42, 24F

10/30 20:58, , 25F
我把cout改成開一個檔案來寫,結果.a的時候那個檔案沒出來
10/30 20:58, 25F

10/30 20:58, , 26F
所以很肯定是沒有初始化 O_O 不是順序的問題,真的好神奇
10/30 20:58, 26F

10/30 20:58, , 27F
其實也沒什麼,只是這樣我gtest就不能包在ar裡面用.. :D
10/30 20:58, 27F

10/30 20:59, , 28F
確定狀況會是怎樣就好了 O_O.. 沒差..
10/30 20:59, 28F
文章代碼(AID): #1AwTZV63 (C_and_CPP)
文章代碼(AID): #1AwTZV63 (C_and_CPP)