• gcc和g++的爱恨纠葛


    gcc想必大家都听过吧,gcc是一个编译器,进行C语言编译的编译器

    但是有的时候代码会发现编不过,有可能是因为标准太低,不支持某些写法

    这个时候就可以

    gcc test.c -std=c99

    有个选项是-o,这样可以给它重命名:

    gcc test.c -o newfilename

    C++中文件的后缀一般有三种:.c,.cpp(c++特有),.cc(c++特有)

    gcc不能用来编译C++代码(gcc不认识C嘎嘎的某些流),c嘎嘎在编译的时候就用g++啦

    g++  test.cc -std=c++11

    还有一种后缀是cxx

    查看g++版本:

    g++ --version

    没有g++就安装一下g++:

    yum install -y gcc-c++

    程序的翻译过程 

    预处理

    预处理阶段完成操作:宏替换,去注释,头文件展开,条件编译

    gcc -E test.c -o test.i

    形成临时文件不生成可执行程序

    -E:从现在开始进行程序的编译,预处理完成就停下

    打开看看

    8d5c9f17248245478f8757108c01547c.png

    多出来的来自

    预处理之后头文件就没用叻

    ls /usr/include/

    e6ebc6348e184d7c8f2314b2c9f85d01.png

    vim  /usr/include/stdio.h

     f7276c34c135492da905753ef4992d3b.png

    分屏瞅瞅

    vs test.i //底行模式

    2e7ef828bc1d492aa551494a0d4d0a0f.png

    我们知道有很多软件(比如VS比如Xshell)有很多版本,社区版,企业版,专业版...在企业版或者专业版中往往有更多的功能,但需要收费

    那在公司里维护代码需要维护几份呢?

    首先从维护代码的成本来分析:当需要维护两份代码时,将bug解决需要实时同步,且测试两次,成本过高,所以一般只需维护一份代码即可

    可是怎么维护一份代码呢?

    条件编译可以对代码实现动态裁剪

    看我的代码:

    1. #include
    2. int main()
    3. {
    4. #ifdef v1
    5. printf("功能1\n");
    6. #elif v2
    7. printf("功能1\n");
    8. printf("功能2\n");
    9. #else
    10. printf("功能1\n");
    11. printf("功能2\n");
    12. printf("功能3\n");
    13. printf("功能4\n");
    14. printf("功能5\n");
    15. #endif
    16. return 0;
    17. }

     fb67645e66dc4553b2cb36f4e63ab471.png

    9c6d0d66503d4eb9905406a32c6d39bd.png

    维护一份代码,实施动态裁剪,这就是条件编译

    1. #include
    2. #define v2 1
    3. int main()
    4. {
    5. #ifdef v1
    6. printf("功能1\n");
    7. #elif v2
    8. printf("功能1\n");
    9. printf("功能2\n");
    10. #else
    11. printf("功能1\n");
    12. printf("功能2\n");
    13. printf("功能3\n");
    14. printf("功能4\n");
    15. printf("功能5\n");
    16. #endif
    17. return 0;
    18. }

    8d45fc45037e4650bd1a4bd3cbb726fa.png

    01f47b7f8d494726a04f7b67f35ce8c6.png

    命令行式宏定义: 

    gcc -Dv1=1 proj.c 

    使用命令行式宏定义能更方便的进行代码裁剪 ,gcc能裁剪代码哦(去注释,宏定义这些)

    编译 

    -S:从现在开始进行程序的编译,编译结束就停下

    编译的工作是做语法检查,将C变成汇编语言

    gcc -S test.i -o test.s

    d5bef51278884d12a01b9599fba15588.png

    汇编

    从现在开始进行程序的翻译,汇编完成就停下来

    汇编过程的工作是汇编语言编译成为二进制目标文件(.obj) 

    gcc -c test.s -o test.o

    (文件后缀是.obj,可重定位目标文件,还不是可执行程序)a7955610443c4dfb8b87b91719c27ac7.png

    它不可执行: 

     e2566a7511e444c9b8d96c9358c23be1.png

    不是权限的问题,它就算加上权限本身也不可执行 :

    e98adc3cd4e64bb0854ae17074ba2fc0.png

    文件可以被执行,即要有可执行权限,也要文件本身是可执行文件

    链接

    链接形成可执行程序(程序和库结合的过程)

    gcc test.o -o my.exe

    是不是很连贯:看看ESc(令人震惊的巧合)

    后缀:iso(学ios的有福啦,我所以)

    有个问题:为什么要搞这么复杂?

    听个故事:

    过去在没有C的时候,大部分人用的都是二进制编程,当时是用那种打孔纸带(参见叶文洁,没看过三体的看一眼,,,)

    cb26806cb39f49bf8f61b2821b584529.png

    能透过去的就是1,透不过去的就是0

    二进制编程使用01序列识别

    但是这个确实是麻烦,于是人们就设计出了汇编语言(里面的符号叫助记符,从汇编开始有编译器的哦)

    再后面就是C语言,支持各种语法(宏定义啦,注释啦,,,)

    语言发展要有编译器,编译器非常不好写,介于语言发展的过程趋势,显然发明汇编语言转C的编译器更简单可行(你总能从二进制开始搓C吧,你站在巨人的肩膀上)

    编译就是在回溯历史,这样效率更高啊

    混沌初开,到底先有语言还是先有编译器

    那肯定先有语言啊,有语言才有给这门语言写编译器的冲动(怒发冲冠为语言)

    在语言发展到汇编阶段的时候,汇编的编译器是用二进制写出来的(只有二进制编程方案)

    然后还有个事:编译器是软件吗?

    肯定是啊,既然是软件,那就需要维护,将我们写出的汇编代码交给用二进制编写的汇编编译器,由编译器帮助我们生成可执行程序,但是由于二进制写的编译器太挫了(维护起来效果好差),所以可以用汇编语言写一个新的编译器,这样就站在前人的肩膀上形成了新的编译器(这个更新迭代的过程叫做编译器的自举:自己编排自己)

    至于链接本质上是程序和库结合的过程,当语言被发明时,一方面要有自己的语法,再一方面语言需要有自己的标准库(C88,C89,C99...)链接的时候是在调用,库里实现了很多东西

    这样可以查看链接的动态库:

    ldd my.exe

    46c25336ec0544b79542962915c40a3e.png

    系统下的一个二进制库承装了很多方法: 

    ls /lib64/libc.so.6 -l

     3028091bf58a4132a9e68e804073839b.png

    库真正的名字是去掉前缀,去掉尾

    所以这个库的真实名字(掐头去尾)是:C 

     这里的libc-2.17.so被称为C标准库(一个超大公共图书馆)

    安装开发环境需要安装编译器、C标准库、C头文件

    在Linux库中,大致分为两种:

    1.动态库:.so

    2.静态库:.a

    Windows也有动静态库之分:

    1.动态库:.dll

    2.静态库:.lib

     报错可能是库被误删了

    在链接时,存在两种链接方式:动态链接、静态链接

    还是一个小故事:想必网吧大家都听过,在以前其实还有一个东西叫话吧(搞很多座机在那里)

    墨墨酱是一名中学生,现就读于逆天寒中学(市里最好的一所中学),墨墨酱以市第一的成绩考入了逆天寒中学(也有很多墨墨酱的初中同学也考去了那里),墨墨酱没什么别的爱好,就是喜欢上网(爱启动steam的小姐姐一枚吖~)但是悲从中来,逆天寒中学实施封闭化管理,不允许学生带手机电脑肯定也不行啦,除非有特殊情况(比如你爹是校长之类的),墨墨酱很苦恼,墨墨酱去问高三老油条学长:学长学长,学校不让带电脑不让带手机,我想上网怎么办,学长如是说:你别害怕,学校一千多号人呢,学校不让你上网,那这附近还没个小网吧了?!你从东门出,向北走,就能看到有家小蚂蚁网吧,去那整几个小时,买不了吃亏,买不了上当,学长还和墨墨酱说,虽然咱们学校封闭式管理,但是每周日会允许你出去采购,墨墨酱开心的上起了学

    在老师分配完宿舍,上了几天b课,终于来到了愉快的周末,但是周末有作业不快乐,墨墨酱不想赶ddl,于是墨墨酱开始规划(现实中的墨墨酱也是j人小女孩一枚呀)她计划早晨八点起,吃完早饭把语文作文一写,把物理大题一做,把数学那小题证明一下,十二点次幻,次完幻去睡会觉,两点半起来去上网,然后五点回,把化学方程式一搞,生物知识点一背,墨墨酱甚至规划出了一份待办清单(一想到能打游戏就开心的墨墨酱)于是墨墨酱撸起袖子加油干,世界人民都点赞,开始翻身下床实施她的计划,做完了一系列事情,墨墨酱直奔网吧,跟网吧老板说,给我开个靠窗机子,机子开好了,墨墨酱愉快的走向了她的⑨号机子开始欢乐steam,美好的时光总是过的匆匆,墨墨酱打完游戏回去洗洗睡感觉恍如隔世,随着墨墨酱的成长,认识的朋友也越来越多,于是开始组队排位,哦~我的朋友~原来你也在这里~

    在这个故事里,学长起到一个编译器的作用,逆天寒中学相当于内存,学长告诉墨墨酱网吧地址(目标库地址)是在帮助她找寻目标库,这个过程被称作动态链接,小蚂蚁网吧相当于动态库,⑨号机子相当于库中特定的方法(printf、scanf、malloc...),墨墨酱写出来的清单相当于代码,墨墨酱去网吧打游戏相当于跳转到相应库执行,这整体的过程就是在动态运行,动态链接的过程在编译时就已经做了(学长告诉墨墨酱网吧地址)

    故事仍在继续,盛唐绮梦,不负相逢

    不止有墨墨酱在上学,所有学校里如墨墨酱一般的少年都去一家网吧开机子,但毕竟林子大了什么鸟都有,墨墨酱的班长很看不惯墨墨酱的这种行为,认为这是违规违纪,自己不好好学习还要拉上别人(你给我放尊重点,老墨可是市状元!!!),行吧,班长要举报墨墨酱了,他向附近的一个派出所举报墨墨酱,于是警察叔叔就出动了,前去小蚂蚁网吧核实情况,他们问网吧老板:你有营业执照吗?

    老板一脸懵逼:营业执照是嘛玩意

    民警看老板这个样子,就和老板说,接到民众举报,我们要对你的店实行管控,最后的结果就是网吧被查封叻,过了一段时间,老板通过走关系把自己的设备保留了下来,没多大损失,最终给网吧老板的结果就是:资产可以还,但是不准在逆天寒中学旁边开了(苦了孩子们,最惨的是嗷嗷待哺的人民群众)这个过程叫做动态链接共享动态库,但是一旦动态库缺失,所有的动态链接这个库的程序都无法执行了(动态链接很依赖共享动态库

    乏味的一学期过去了,墨墨酱向家人讲述了这件悲伤的事情,由于墨墨酱是市状元,学习嘎嘎棒,所以在墨墨酱爹地和学校校长有着一定关系的基础上,墨墨酱居然成功在宿舍get电脑一台(甚至是墨墨酱爹地从上一家老板那购入的墨墨酱最喜欢的⑨号机),可以,墨墨酱舍友要羡慕死了,建议给墨墨酱顺便安排个单间+上床下桌羡慕死他们(什么爽文女主剧本),后来逆天寒中学旁边又开了一家小猫猫网吧,可墨墨酱再也不去了,在小猫猫网吧开起来之后,宿舍人手一台机子勒(都说服了自己家长,机子是从网吧扛过来的,九九成稀罕物)由于人手一机,网吧就不再被需要勒,每个人把电脑拷贝到自己的可执行程序的过程叫做静态链接(笑死我了,网吧老板爆改卖电脑的,在这里,网吧老板起到一个静态库的作用)

    在编译的时候,将库中的方法拷贝到自己的可执行程序中的过程叫做静态链接(不再关心任何库)

    这个命令也可以帮助我们查询:

    file my.exe

    这是在动态链接使用共享库: 

    dae4b76d0d8548edaa14a3d76915da96.png

    (动态库&&动态链接)||(静态库&&静态链接)

    动态库优缺点

    1.不能丢失

    2.节省资源(静态链接重复率很高)

    静态库优缺点 

    1.一旦形成,和库无关

    2.浪费资源

    在Linux上,一般静态库是默认没有安装的

    安装静态库:

    yum install -y glibc-static libstdc++-static

    静态链接应用场景:把需要的库拷贝到可执行程序(不依赖库),具有跨平台性

  • 相关阅读:
    protolator简介
    SICP-- 元语言抽象--Scheme的变形--惰性求值
    SQL SERVER Inregration Services-OLE DB、Oracle和ODBC操作
    mysql 物理备份及恢复
    Vue(一)——Vue核心
    鸿蒙开发-UI-动画-组件内转场动画
    一生一芯10——verilator v5.008环境搭建
    酚醛建筑模板的生产工艺有哪些改进的空间?
    通过postgres_fdw实现跨库访问
    linux postgresql 常用指令
  • 原文地址:https://blog.csdn.net/chestnut_orenge/article/details/138099523