握艹,C你main啊!

嵌入式Linux

共 5665字,需浏览 12分钟

 ·

2024-06-25 08:23

我看了这代码这问题,直呼“握草”,main的!
事情是这样的,前段时间来了个新项目,大家都太忙了,没人积极搞啊。于是,领导启用了他前不久招的“得意门生”,把这活儿交给他了。
这项目其实也没很多活要干,最主要的是要从一个C++项目代码移植到平台的基础工程里,当然这个基础工程是C语言的。
这小伙,一顿操作猛如虎,风风火火搞了几周,基本功能终于跑起来了!
领导心想:哎呀果然没看错人。接着没几天领导就向上面领导吹捧一番,说这项目怎样怎样难,这谁谁又怎么怎么排除万难的,最终搞出来了。反正,领导开心,小伙的绩效也差不了哪去了!
直到最近,出了一个bug,离奇古怪,某功能在你意想不到的情况下出错。领导又派出了他的“得意门生”,噼里啪啦的,搞了一个多星期了,啥头绪也没有……
这问题可被甲方发现了的,而且临近交付样品了,这把领导急的不要不要的。
领导憋出了个大招,“三个臭皮匠顶个诸葛亮”,发动整个小组找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是什么玩意

这个其实不好看懂,但能肯定的是,在仿真时,它没被调用!
2. 查网络内容或者查看编译手册
也不好找到直接的答案,但能知道这个_ctor是C++的构造函数,另外还有个叫_dtor。
综合上面的信息看,好像是在说C++的构造函数没有调用,这个构造函数又跟___sti___12_cpp_main_cpp_mm有关。
3. 直接问AI
其实也不用那么麻烦,现在什么年代了,有AI啊,直接问
虽然没有找到具体的问题点,但是可以大概找到,这个warning说,这个代码里面有C++的构造函数没调用,也提到这个C++动态初始化函数___sti___12_cpp_main_cpp_mm没调用。
下一步呢?
别急,看看这个函数名字,是不是带个main的……
大胆猜测,那是不是跟main函数有关?
也许你会去看看那个main函数,好像也没什么特别错误啊!
但是呢,不妨将想象力放开点,是不是说main函数要调用这个___sti___12_cpp_main_cpp_mm呢?
等等,你是说main函数要调用一个C++的动态初始化函数?构造函数来的?
___sti___12_cpp_main_cpp_mm这种函数也不像是直接在main函数调用的啊!
啊!不对,这个是C语言文件里的main函数,握草,应该是C艹函数!
是不是将main函数里的xxx.c改成xxx.cpp就好了呢?
好激动哦,我是不是快找到问题原因了……
直接试了下,还真是,C你main的,居然跟C艹不一样!
我压制住我心中的激动,让领导和那帮家伙再愁一会,我还没搞清楚C main和C++ main的区别,不然被领导追问,我说不出来来龙去脉,岂不是说我乱猜的,瞎猫碰到死耗子,没啥技术含量!哼!
我接着,仿真了C语言和C++的main函数。
发现C++的main多了点东西:


仿真C++ main的汇编可以看到__main是库里面的函数,其会调用这个___sti___12_cpp_main_cpp_mm函数。
这样,我可以告诉领导我找到问题原因了吗?
我还是选择等等。因为,这样无法说明怎么直接导致了项目的那个问题啊!并且,有些项目C和C++混合的工程,用C语言main函数也没问题啊,而且也没提示那个warning!
如果领导问我,我也说不出为什么,他还是会说我猜的!
为了保证,我的回答万不一失,我选择低调继续研究下。
再回头看看AI回答的那段话,它提到了构造函数和静态对象,难道是静态对象的初始化赋值问题?
于是,我尝试了好多次不同的场景,终于模拟出了这种情况。(我把完整测试源码附在文末)
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函数里面就是静态变量的初始化!
这里这个-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类的静态成员st_m。此时很容易就能理解到,这个___sti___12_cpp_main_cpp_mm函数就是执行了Msg Test::st_m = mm;的赋值。汇编中的-0x1430000就是对应MAP中.data段的_mm变量,就是Msg mm={0xaa,0x55};这个变量。通过仿真就可以证实这些内容。
所以,C++的main跟C的main不一样,C++的main更有内涵,其中还藏着一个__main,且其里面还执行了静态成员的初始化。
  • C的main,性格直爽,心里不藏任何秘密;
  • C++的main,内敛且有内涵,还悄悄地帮你做静态成员初始化。
所以,你喜欢谁的main?
好了,话题扯远了,这下我应该可以向领导汇报了吧。
于是,我打算好好科普C和C++的main main的时候,领导却说,那谁谁已经再同步C++项目的启动部分文件就OK了,而且已经检讨移植项目文件不彻底问题了,问题已经解决了。于是,让我去忙别的去了。
我……欲言又止……
main的,艹!

测试源码
// c_main.cextern int test_func(void);#ifndef CPP_MAINint main(void){    test_func();    return 0;}#endif


// cpp_main.cpptypedef 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

我知道你看完本文就退出的了,就算收藏也是吃灰的,不如你点个转发点赞在看再走,我是会很感激你的哦!

浏览 368
4点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
4点赞
评论
收藏
分享

手机扫一扫分享

分享
举报