炒股为生1314新浪博客或tyj新浪博客
概述
为什么需要解读gcc/g++编译器对c/c++文件的影响呢?由于系统内核一般是使用C语言来编写的,系统内核中用C语言实现了很多库。而上层应用程序有可能是用C++来开发,如果在内核库函数头文件中不用extern“C”来声明库函数的话,在编写C++应用程序时,包含库头文件,在C++文件链接时就会以C++标准来链接库的函数名,而在库文件实现时是用C来实现的,二者函数名不同,在链接时就会出现找不到函数的现象。
实验环境
本次实验平台:Debian 9.4 gcc/g++版本:6.3.0 IDE环境:Qt Creator 4.2.0 qmake版本:3.0。这里可以看到最新的Debian系统对软件版本更新也是很及时的,对于电脑不能上外网情况,debian与centos都推出了离线包,两个系统都使用了很长一段时间,这里还是给大家推荐centos,centos很多东西是继(chao)承(xi)红帽的,可能是这个原因,所以centos很稳定、bug少。
编译步骤
编译器一般可分为预处理、编译、汇编、链接四个阶段,GNU手册也做了介绍,手册如图 1所示。
图 1
预处理:将宏定义展开,将相关和类型定义引入等操作,生成后缀为.i的预处理文件。
编译:将预处理文件编译成汇编文件,生成后缀.S的汇编文件。
汇编:将汇编文件编译成目标文件,生成后缀为.o的目标文件。
链接:将各个.o文件与相关库文件进行链接,链接方式可以选择静态或动态链接。
上面是标准的面经,同时也是网上最容易搜索到的答案,但实质根本没理解gcc/g++编译。从上述面经来看,感觉就是gcc只能编译c程序,g++只能编译c++程序。gcc/g++编译c/c++程序可以分为四种情况,gcc编译.c程序,gcc编译.cpp程序,g++编译.c程序,g++编译.cpp程序。下面通过对比这四种情况来真正了解gcc/g++编译器。
gcc/g++编译.c文件
为了彻底理解清楚两种之间的区别,下面通过编译的几个阶段去解读,test.c文件如图 2所示,这里需要注意,在test.c中我没有引入c++头文件和语法,如果用gcc编译,那么就连万里长征第一步预编译都不能通过,有且仅有当用gcc编译.c文件时,编译器才会按照C文件规则进行预编译,这里提前提出结论。为了更好的对比,对比.c文件代码中采用c规则。
图 2
预编译处理
使用gcc和g++分别对test.c进行预处理,执行结果如图 3所示。
图 3
从图中可以看到24c24等字符,c代表转换意思,前后数字代表行数,前后出现一对数字代表行号区间。同时可以看到g++预编译.c文件时候,会在部分头文件和类型定义前添加extern “C”,这个标识符的作用把标识符作用域的数据类型采用gcc去编译,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。
编译阶段
编译阶段是把.i文件编译成汇编文件,编译过程和结果如图 4所示。
图 4
通过图中对比发现,只有程序中自定义的函数接口命中不一样,其它代码完全一样。gcc编译器编译后的函数名字和编译前函数名一致(有些可能是在函数前面添加_,具体机制是跟编译机制有关),g++编译器是在函数中添加_z3*ii。这里其它代码相同原因是程序中使用的语法c++是部分兼容c的,上图仅仅代表是一种特殊情况,因为.c文件中全部采用的c语法规则。
汇编阶段
程序处于汇编阶段时,gcc/g++内部都是调用as汇编命令,在这里两者是没有区别的,可以通过如下命令做测试,用c++_test.S做测试对比。
gcc -c c++_test.S -o c_test.o
g++ -c c++_test.S -o c++_test.o
diff c_test.o c++_test.o
通过对比试验,两个.o文件完全一样,在汇编阶段gcc/g++的作用是一样的,读者可以尽情做实验。
链接阶段
gcc/g++都是调用ld命令,同样两种区别在于传入的参数与调用库的不同,g++默认与c++库链接(兼容C语言部分,还是调用C库),gcc默认是与c库链接。实验是检验真理的最好工具,下面同样选取c++_test.o做实验。
gcc c++_test.o -o c_test
g++ c++_test.o -o c++_test
diff c_test c++_test
通过diff对比,两个可执行文件内容不一样的。通过strace跟踪系统调用结果如图 5所示。可以清晰看到两者仅仅是一些mmap地址映射不一样,即使两次用g++编译相同文件,可能生成的文件也不一样,这个不一样仅仅体现在地址映射上。
图 5
gcc/g++编译.cpp文件
编译cpp文件同样通过四个阶段做比对,同时还和编译.c文件得出的结论做对比,test.cpp文件内容如图 6所示。
图 6
复制test.cpp文件为test.c文件,然后进行四个阶段做对比。
预编译
g++ -E test.c -o test.ii
g++ -E test.cpp -o c++_test.ii
gcc -E test.cpp -o c_test.i
这里保存为.ii或者.i都是无所谓的,只有当预编译的输出需要手动指定作为编译阶段的输入(-x选项指定输入文件类型),并且没有指定编译阶段输入是什么类型文件,那么编译器就会根据系统自定义的后缀去解析,默认编译器会把.i后缀当成c预编译的结果,.ii后缀当成是c++预编译的结果。通过对比这个3个.i文件发现预编译结果完全一样,只有文件名不同,test.c与test.cpp的区别。
编译
gcc -S test.cpp -o c_test.S
g++ -S test.cpp -o c++_test.S
g++ -S test.c -o test.S
编译结果如图 7所示。生成的.S文件内容又是完全一样,只有.file不一样,这个标识符是指文件名,1c1代表第一个文件的第一行与第二个文件的第一行转换关系。
图 7
汇编
gcc -c test.cpp -o c_test.o
g++ -c test.cpp -o c++_test.o
g++ -c test.c -o test.o
汇编阶段结果同样是一致。
链接
g++ test.cpp -o c++_test
g++ test.c -o test
objdump -S test > test.obj
objdump -S c++_test > c++_test.obj
这两种编译结果通过查看二进制只有文件名是不一样的,两种方式都装载了libstdc++.so.6和libc.so.6库文件,这是g++兼容c的另外一个表现;同样可以通过反编译手段对比两个二进制文件,对比结果如图 8所示,两个obj文件同样只有文件名不一样。
图 8
还剩下一种情况没有对比,那就是gcc链接.cpp文件。
gcc c_test.o -o c_test
链接不能正常通过的,提示找不到c++库。由于链接阶段gcc不能够自动链接c++库,g++可以自动链接c++库,如果加上-lstdc++选项就能够正常编译通过。
gcc c_test.o -o c_test -lstdc++
同样可以对比c_test 与c++_test文件,但是读者会发现,这两个文件肯定不一样。我们通过反编译手段观察两个文件的区别,同样仅仅是地址不一样,比如_init地址不一样等。图 9是我截取的局部反编译对比图。程序最先从_init中rsp堆栈指针顶开始做堆栈处理,然后跳转到程序中我们看到的main函数入口地址,进入函数之前先保存栈指针,在进行push,程序中在跳转到add函数的的地址,最后程序执行完成在_fini中恢复栈平衡。(大概思路是这样的,已经三年没有碰过底层地址相关的知识,凭记忆补充一点相关知识。在嵌入式开发过程中有几个地方需要用到地址概念,uboot链接脚本确定程序第一条指令入口、编译文件顺序、位置无关地址跳转问题,栈顶设置;加载linux地址时分析相对复杂一点,编译kernel需要指定入uImage或zImage入口地址,uImage与zImage仅仅相差64Bytes头,这里牵扯到解压kernel,代码搬运等操作)。
图 9
通过上面两个对比实现可以得出如下结论:
后缀为.c的,gcc把它当成c程序;g++当作c++程序,即跟.cpp没有区别。
后缀.cpp的,gcc与g++都当成c++程序。
gcc不能自动链接c++库,g++会自动链接c++库。
c++程序中,预编译后会存在extern “C”标识符,即是用gcc按照c程序规则编译,这是兼容C程序的表现。
gcc也可以编译c++程序。
gcc编译.c文件,.c文件中一定不能出现c++语法和库操作。
__cplusplus测试
如果编译器按照c++规则编译,那么这个宏__cplusplus就会被编译器定义。上面已经得出结论了,下面通过这个宏定义再次验证上面1、2结论。test.c与test.cpp文件内容如图 10所示,依次执行如下命令。
gcc test.c && ./a.out @结果是:a+b=1314
g++ test.c && ./a.out @结果是:a+b=520
gcc test.cpp && ./a.out @结果是:a+b=520
g++ test.cpp && ./a.out @结果是:a+b=520
从结果同样可以证明,只有当用gcc编译.c程序时才会按照c规则编译程序。
图 10
有读者可能就问了,既然g++能够编译c程序,gcc还有必须要存在吗?这个答案是肯定的。原因一:操作系统全是按照c规则编写与编译(除开head.S等文件中的汇编),很多系统库文件都是按照c规则写与编译的,如果采用g++去编译这一部分,那么生成的可执行文件会非常大,以及程序运行效率大大降低;还可能存在不能正常编译通过情况,就是上述对比实验中函数链接接口不一样。编译器优化性能也是有限的,系统内核是整个上层应用的心脏,必须做到最高效率,不许存在过多冗余代码(编译器的问题)。原因二:做单片机出身的工程师对c语言扣字节操作应该是一种信仰,做上层应用的工程师更偏向c++面向对象,一个大项目基本都是通力合作完成。所以gcc用来编译c程序(效率问题,c实现对系统接口二次封装),g++编译c++程序。
工程包含.c与.cpp文件如何处理
如果是工程师自己写编译规则,那么在Makefile中应该检测.c和.cpp文件分别用gcc与g++编译,最后统一链接。如果是IDE环境,由IDE环境决定,在qt中qmake是将.c文件用gcc编译,g++编译。那么g++如何调用c程序封装的函数或者库呢,从上述讲解知识可以看到c++程序直接调用c程序接口,这个肯定报错提示找不到库函数,c和c++处理函数接口机制不一样,所以在c++程序中调用c程序应该在函数声明前加上extern “C”,这是在提醒g++编译链接这个函数时按照c函数机制去链接。同样如果在程序中函数实体前加extern “C”,这是在提醒编译器整个函数用gcc按照C规则去编译。切记理解编译与链接是两码事情。
图 11是一个QT工程模板,图中pcie.c文件的后缀只能用.c,如果换成.cpp,无论你是用gcc还是g++,走到链接阶段是找不到libpci.so提供的库函数的,虽然可以用把标准头文件路径pci.h中使用的函数声明前重新加上extern “C”,但是得不偿失。定义成.c文件qt环境会用gcc去编译,在pcie.h文件中的声明函数前加上extern “C”就可以正常链接。
图 11
动态库封装
看3条简单命令就可以很好理解,封库大多数是针对客户做二次开发使用;还有可能各个部门之间的合作需要封库。还有一种比较恶心的人,写代码特别喜欢封装库,玩隐蔽,不可替代性;在svn上只看得到几行画蛇添足的代码,在代码中调用库、管道接口、二进制文件。这种代码可阅读性很差,仅限本人阅读。
gcc -fPIC –shared test.c –o libtest.so //封库
gcc main.c –L. -ltest –o main //使用
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
---------------------
作者:HeroKern
原文:
https://blog.csdn.net/qq_21792169/article/details/85097822
原创 大财可富司机
海水潮起潮落,股市有涨有跌,入市的韭菜每年都在不断更迭,但写股票的博主来来回回也就那么些人。
前段时间有读者在后台留言,想让司机扒一下中金在线“头牌”博主天赢居。当时司机就觉得这个名字相当耳熟,后来看了相关资料才知道,早在N年前司机就曾在新浪博客看过他的文章,只是没想到,这么多年来他还在写。看来,割韭菜也是会上瘾的!
那还是“带头大哥777”的时代,当年叱咤风云的财经大V,因为涉嫌非法经营罪,于2007年被逮捕。
就在“带头大哥777”消失于江湖之际,新版带头大哥再现江湖,他就是“tyj天赢居”。
青出于蓝而胜于蓝。“tyj天赢居”势头比带头大哥更猛,他在新浪、网易、东方财富网、中金等主要财经网站都开设博客。当年,东方财富网的点击数甚至超过2000万,即使每篇文章还要付费阅读,但粉丝还是积极掏钱。有媒体对此进行了报道:
如今的“tyj天赢居”主战场在中金在线,号称中金在线第一圈主,粉丝1万,2006篇文章,12亿阅读。他的微博粉丝15W、微信公众号“天赢居”每篇文章阅读量约2W。
“tyj天赢居”个人简介显示,他出生于1973年,20岁(1993年)开始炒股,在遭受股市毒打后,2006年形成自己独立的炒股体系,2007年开始在博客发布文章。他的文章主要是以技术分析为基础,对股市进行预测。
预测的准确率如何?司机以2022年以来的部分文章为例,进行分析:
1月4日,他在文章《属水的板块大涨特涨》中写道:“日线虽然不好看,但毕竟在均线密集区之上,周线、月线也在均线上方,趋势方面是在逐步走出底部区域的状态当中。底部结构成型后趋势就将向上发散,春季行情的第三浪上涨周期正在加载当中,第四次冲击大横盘箱顶趋势线的时间不远了。持股享受春季行情的红利。”
1月11日,他在文章《悬在头顶的最后一跌》中写道:“下个交易日就是调整21个交易日的节点;空间3547与233日均线共振支撑,下跌空间很小。指数已经到达底部区域,即便出现最后一跌,惯性下挫也是机会大于风险。”
2月28日,他在文章《三月机会多》中写道:“目前在89周均线3456附近横盘爬升到第五周,上方55周均线和34周均线以及21周均线与13周均线粘合在3535-3555附近难以逾越,而下方144周均线3255的支撑也更为强大。所以周线即将选择方向,跌下去就可以抄底,站稳3535也可以把握新的机会。”
实际走势,大家也看到了,大盘从开年就开始下跌,一直跌到4月份的2863点才见底。他的上述预测可以说是完全错误。
此外,他今年以来还有这些预测,也被证实是错误的。
要说他的预测完全不准确吧,倒也不全是,比如年初他曾预测到4月27日这个重要的时间变盘点。
可是,如果股民每一次操作都完全跟着他的预测来,估计血本无本了。
预测真的只是一个概率的游戏。有些人乐此不疲,更想不通的是,还有很多人就好这一口。
“天赢居”很早开通了付费圈子,2020年付费圈子一年的订阅费用就达到7000多元,今年还要全面涨价。
关于天赢居的水平如何?网上有不少讨伐他的文章,时间跨度很长,说明多年来,他始终奋战在第一线,从未懈怠。
一直以来,天赢居的身份都很神秘。网上公开信息也仅仅显示他是重庆人,毕业于重庆大学。之前他呼吁网友救助贫困学生,提供银行账号叫大家打款是“谢XX”的账号,有记者发现他的新浪博客名也为“谢XX的博客”。便误认为他姓谢。
但是,天赢居曾说过,“tyj是真实名字的缩写”。
司机通过线索梳理、层层查找,终于找出了他的真实身份。
天赢居微信公众号的帐号主体是“沙坪坝区众富商务信息咨询信息服务部”。
天眼查显示,这家公司成立于2017年,注册资本1万元,经营范围是商务信息咨询。公司经营者为唐良华。唐良华同时还是重庆朗顺投资咨询有限公司(吊销,未注销)的股东,朗顺投资的大股东名叫唐渝江。
“唐渝江”的拼音缩写也是“tyj”。因此,司机很肯定,唐渝江就是天赢居的真实姓名。
此前,天赢居通过博客、网站进行股市预测,提供咨询,有投资者质疑他和“带头大哥777”一样,有非法经营罪的嫌疑。
混迹于江湖多年的天赢居,也肯定知道这样做的风险。于是,他通过巧妙的办法规避了这一问题。通过挂靠投顾公司,持证上岗,这样就名正言顺,可以愉快地继续割韭菜了!
上一篇:炒股软件免费版跟十大炒股app
下一篇:股票601288与新浪股票首页