事情是這樣的,前段時間來了個新項目,大家都太忙了,沒人積極搞啊。于是,領導啟用了他前不久招的“得意門生”,把這活兒交給他了。
這項目其實也沒很多活要干,最主要的是要從一個C++項目代碼移植到平臺的基礎工程里,當然這個基礎工程是C語言的。
這小伙,一頓操作猛如虎,風風火火搞了幾周,基本功能終于跑起來了!
領導心想:哎呀果然沒看錯人。接著沒幾天領導就向上面領導吹捧一番,說這項目怎樣怎樣難,這誰誰又怎么怎么排除萬難的,最終搞出來了。反正,領導開心,小伙的績效也差不了哪去了!
直到最近,出了一個bug,離奇古怪,某功能在你意想不到的情況下出錯。領導又派出了他的“得意門生”,噼里啪啦的,搞了一個多星期了,啥頭緒也沒有……
這問題可被甲方發(fā)現(xiàn)了的,而且臨近交付樣品了,這把領導急的不要不要的。
領導憋出了個大招,“三個臭皮匠頂個諸葛亮”,發(fā)動整個小組找bug……
尼瑪,我也被牽連了,翻了半天也沒頭緒,這代碼一坨坨的具體是啥含義,我也懶得去研究。
干脆直接編譯,準備仿真看看的,一段編譯警告有點陌生,又特別礙眼,類似長這樣的:
[elxr] (warning #222) The program contains no reference to _ctors.The following C++ dynamic initialization routines will probably not get called: ___sti___12_cpp_main_cpp_mm from cpp_main.omain() (from c_main.o) was probably not compiled as C++.
呵呵,這只是個warning,估計那小伙也不care!
我第一次見這種warning,很好奇,也還不清楚是否跟這個問題有關,不過我預感八九不離十了。
怎么排查或者確認這個warning就是因為項目的那個問題呢?
1. 直接仿真,查看匯編,這個___sti___12_cpp_main_cpp_mm是什么玩意

這個其實不好看懂,但能肯定的是,在仿真時,它沒被調用!
也不好找到直接的答案,但能知道這個_ctor是C++的構造函數(shù),另外還有個叫_dtor。
綜合上面的信息看,好像是在說C++的構造函數(shù)沒有調用,這個構造函數(shù)又跟___sti___12_cpp_main_cpp_mm有關。
其實也不用那么麻煩,現(xiàn)在什么年代了,有AI啊,直接問
雖然沒有找到具體的問題點,但是可以大概找到,這個warning說,這個代碼里面有C++的構造函數(shù)沒調用,也提到這個C++動態(tài)初始化函數(shù)___sti___12_cpp_main_cpp_mm沒調用。
別急,看看這個函數(shù)名字,是不是帶個main的……
也許你會去看看那個main函數(shù),好像也沒什么特別錯誤??!
但是呢,不妨將想象力放開點,是不是說main函數(shù)要調用這個___sti___12_cpp_main_cpp_mm呢?
等等,你是說main函數(shù)要調用一個C++的動態(tài)初始化函數(shù)?構造函數(shù)來的?
___sti___12_cpp_main_cpp_mm這種函數(shù)也不像是直接在main函數(shù)調用的啊!
??!不對,這個是C語言文件里的main函數(shù),握草,應該是C艸函數(shù)!
是不是將main函數(shù)里的xxx.c改成xxx.cpp就好了呢?
直接試了下,還真是,C你main的,居然跟C艸不一樣!
我壓制住我心中的激動,讓領導和那幫家伙再愁一會,我還沒搞清楚C main和C++ main的區(qū)別,不然被領導追問,我說不出來來龍去脈,豈不是說我亂猜的,瞎貓碰到死耗子,沒啥技術含量!哼!
我接著,仿真了C語言和C++的main函數(shù)。
發(fā)現(xiàn)C++的main多了點東西:

仿真C++ main的匯編可以看到__main是庫里面的函數(shù),其會調用這個___sti___12_cpp_main_cpp_mm函數(shù)。
我還是選擇等等。因為,這樣無法說明怎么直接導致了項目的那個問題啊!并且,有些項目C和C++混合的工程,用C語言main函數(shù)也沒問題啊,而且也沒提示那個warning!
如果領導問我,我也說不出為什么,他還是會說我猜的!
為了保證,我的回答萬不一失,我選擇低調繼續(xù)研究下。
再回頭看看AI回答的那段話,它提到了構造函數(shù)和靜態(tài)對象,難道是靜態(tài)對象的初始化賦值問題?
于是,我嘗試了好多次不同的場景,終于模擬出了這種情況。(我把完整測試源碼附在文末)
typedef struct{ unsigned int id; unsigned char len;} Msg;class Test { public: Test() { } int n; static int st_n; static Msg st_m;};Msg mm={0xaa,0x55};Msg Test::st_m = mm;int Test::st_n = 0x123;
其實,這個___sti___12_cpp_main_cpp_mm函數(shù)里面就是靜態(tài)變量的初始化!
這里這個-0x142FF94值,即0xFEBD006C,實際是對應MAP文件中的.bss段中的_st_m__4Test變量。
.data febd0000+000008 _mm .text 00000b9e+000002 _multiBreak .text 00000b9a+000000 _multiCall .text 00001b2c+00004a _open .text 000018b6+000084 _raise .text 00001b06+000026 _read .text 00001856+000060 _signal .bss febd006c+000008 _st_m__4Test .data febd0008+000004 _st_n__4Test
那么,這個_st_m__4Test變量是什么呢?就是上面代碼Test類的靜態(tài)成員st_m。此時很容易就能理解到,這個___sti___12_cpp_main_cpp_mm函數(shù)就是執(zhí)行了Msg Test::st_m = mm;的賦值。匯編中的-0x1430000就是對應MAP中.data段的_mm變量,就是Msg mm={0xaa,0x55};這個變量。通過仿真就可以證實這些內容。
所以,C++的main跟C的main不一樣,C++的main更有內涵,其中還藏著一個__main,且其里面還執(zhí)行了靜態(tài)成員的初始化。
-
-
C++的main,內斂且有內涵,還悄悄地幫你做靜態(tài)成員初始化。
于是,我打算好好科普C和C++的main main的時候,領導卻說,那誰誰已經再同步C++項目的啟動部分文件就OK了,而且已經檢討移植項目文件不徹底問題了,問題已經解決了。于是,讓我去忙別的去了。
extern int test_func(void);#ifndef CPP_MAINint main(void){ test_func(); return 0;}#endif
typedef struct{ unsigned int id; unsigned char len;} Msg;class Test { public: Test() { } int n; static int st_n; static Msg st_m;};Msg mm={0xaa,0x55};Msg Test::st_m = mm;int Test::st_n = 0x123;Test gt; extern "C" { int test_func(void){ Test t; int x; t.n = 12; if(t.st_n == 0x123) { x = 100; } if(t.st_m.id == 0xaa) { x = 200; } if(gt.st_m.id == 0xaa) { x = 2200; } return x; }}#ifdef CPP_MAINint main(){ test_func(); return 0;}#endif
我知道你看完本文就退出的了,就算收藏也是吃灰的,不如你點個轉發(fā)、點贊和在看再走,我是會很感激你的哦!
