C++教程_w3cschool https://www.w3cschool.cn/cpp/

C++工作原理:

C++语言的程序因为要体现高性能,所以都是编译型的。但其开发环境,为了方便测试,将调试环境做成解释型的。即开发过程中,以解释型的逐条语句执行方式来进行调试,以编译型的脱离开发环境而启动运行的方式来生成程序最终的执行代码。

生成程序是指将源码(C++语句)转换成一个可以运行的应用程序的过程。如果程序的编写是正确的,那么通常只需按一个功能键,即可搞定这个过程。该过程实际上分成两个步骤。

第一步是对程序进行编译,这需要用到编译器(compiler)。编译器将C++语句转换成机器码(也称为目标码);如果这个步骤成功,下一步就是对程序进行链接,这需要用到链接器(linker)。链接器将编译获得机器码与C++库中的代码进行合并。C++库包含了执行某些常见任务的函数(“函数”是子程序的另一种称呼)。例如,一个C++库中包含标准的平方根函数sqrt,所以不必亲自计算平方根。C++库中还包含一些子程序,它们把数据发送到显示器,并知道如何读写硬盘上的数据文件。

【include <> ""区别 】

另外这里对#include“animal.h”和#include <animal.h>进行说明一下区别

<>和“”表示编译器搜索头文件的顺序不同:

<>表示从系统目录下开始搜索,然后再搜索PATH环境变量所列出的目录,不搜索当前目录
""表示先从当前目录搜索,然后是系统目录和PATH环境变量所列出的目录下搜索
.
所以如果我们知道头文件在系统目录或者环境变量目录下时,可以用<>来加快搜索速度。

C++的编译过程及原理 - 妖米的博客 - CSDN博客 https://blog.csdn.net/qq_43133135/article/details/82865618

【编译 预编译 头文件】

注意:在编译过程中头文件不参与编译,预编译时进行各种替换以后,头文件就完成了其光荣使命,不再具有任何作用

【】

Compiling...

animal.cpp human.cpp ...

Linking...

main.exe - 0 error(s), 0 waring(s)

这段文字输出事实上已经说明了编译的步骤了
编译器先对工程中三个源文件main.cpp,animal.cpp,human.cpp进行单独编译 (Compiling...)

在编译时,由预处理器对预处理指令(#include、#define…)进行处理,在内存中输出翻译单元(就是将include等在源文件上替换了以后产生的临时文件)。
编译器接受临时文件,将其翻译成包含机器语言指令的三个目标文件(main.obj、animal.obj、human.obj)
接下去就是链接过程(Linking...),连接器将目标文件和你用到的相关库文件一起链接形成main.exe。
到此,编译也就结束了。

注意:在编译过程中头文件不参与编译,预编译时进行各种替换以后,头文件就完成了其光荣使命,不再具有任何作用

【为什么我们一般不在头文件中出现定义】

C++编译原理(一) - bobird - 博客园 https://www.cnblogs.com/bobird/articles/3305006.html

首先是预编译,这一步可以粗略的认为只做了一件事情,那就是“宏展开”,也就是对那些#***的命令的一种展开。

例如define MAX 1000就是建立起MAX和1000之间的对等关系,好在编译阶段进行替换。

例如ifdef/ifndef就是从一个文件中有选择性的挑出一些符合条件的代码来交给下一步的编译阶段来处理。这里面最复杂的莫过于include了,其实也很简单,就是相当于把那个对应的文件里面的内容一下子替换到这条include***语句的地方来。

其次是编译,这一步很重要,编译是以一个个独立的文件作为单元的,一个文件就会编译出一个目标文件。(这里插入一点关于编译的文件的说明,编译器通过后缀名来辨识是否编译该文件,因此“.h”的头文件一概不理会,而“.cpp”的源文件一律都要被编译,我实验过把.h文件的后缀名改为.cpp,然后在include的地方相应的改为***.cpp,这样一来,编译器就会编译许多不必要的头文件,只不过头文件里我们通常只放置声明而不是定义,因此最后链接生成的可执行文件的大小是不会改变的)

清楚编译是以一个个单独的文件为单元的,这一点很重要,因此编译只负责本单元的那些事,而对外部的事情一概不理会,在这一步里,我们可以调用一个函数而不必给出这个函数的定义,但是要在调用前得到这个函数的声明(其实这就是include的本质,不就是为了给你提前提供个声明而好让你使用吗?至于那个函数到底是如何实现的,需要在链接这一步里去找函数的入口地址。因此提供声明的方式可以是用include把放在别的文件中的声明拿过来,也可以是在调用之前自己写一句void max(int,int);都行。),编译阶段剩下的事情就是分析语法的正确性之类的工作了。好啦,总结一下,可以粗略的认为编译阶段分两步:

第一步,检验函数或者变量是否存在它们的声明;

第二步,检查语句是否符合C++语法。

最后一步是链接,它会把所有编译好的单元全部链接为一个整体文件,其实这一步可以比作一个“连线”的过程,比如A文件用了B文件中的函数,那么链接的这一步会建立起这个关联。链接时最重要的我认为是检查全局空间里面是不是有重复定义或者缺失定义。这也就解释了为什么我们一般不在头文件中出现定义,因为头文件有可能被释放到多个源文件中,每个源文件都会单独编译,链接时就会发现全局空间中有多个定义了。

标准C和C++将编译过程定义为9个阶段(Phases of Translation):

1.字符映射(Character Mapping)

文件中的物理源字符被映射到源字符集中,其中包括三字符运算符的替换、控制字符(行尾的回车换行)的替换。许多非美式键盘不支持基本源字符集中的一些字符,文件中可用三字符来代替这些基本源字符,以??为前导。但如果所用键盘是美式键盘,有些编译器可能不对三字符进行查找和替换,需要增加-trigraphs编译参数。在C++程序中,任何不在基本源字符集中的字符都被它的通用字符名替换。

2.行合并(Line Splicing)

以反斜杠/结束的行和它接下来的行合并。

3.标记化(Tokenization)

每一条注释被一个单独的空字符所替换。C++双字符运算符被识别为标记(为了开发可读性更强的程序,C++为非ASCII码开发者定义了一套双字符运算符集和新的保留字集)。源代码被分析成预处理标记。

4.预处理(Preprocessing)

调用预处理指令并扩展宏。使用#include指令包含的文件,重复步骤1到4。上述四个阶段统称为预处理阶段。

5.字符集映射(Character-set Mapping)

源字符集成员、转义序列被转换成等价的执行字符集成员。例如:'/a'在ASCII环境下会被转换成值为一个字节,值为7。

6.字符串连接(String Concatenation)

相邻的字符串被连接。例如:"""hahaha""huohuohuo"将成为"hahahahuohuohuo"。

7.翻译(Translation)

进行语法和语义分析编译,并翻译成目标代码。

8.处理模板

处理模板实例。

9.连接(Linkage)

解决外部引用的问题,准备好程序映像以便执行。

判断宏定义是否正确和头文件包含是否正确

经过预编译后的头文件不包含任何宏定义,
因为所有的宏已经被展开,并且包含的文件
也已经被插入到达.i文件中。

gcc -E test_head.c -o t.i

最新文章

  1. express全局安装后无法通过require使用
  2. bzoj 3507: [Cqoi2014]通配符匹配
  3. 基于webrtc的资源释放问题(二)
  4. 添加一个功能Action
  5. JavaScript基础介绍
  6. User表格式
  7. ubuntu 13.10 64bit装BeyondCompare
  8. jQuery简单的轮播特效
  9. Linux企业级开发技术(6)——libevent企业级开发之内存管理
  10. Power Calculus 快速幂计算 (IDA*/打表)
  11. 键盘快速启动工具Launchy的简单使用技巧
  12. python数组查找算法---bisect二分查找插入
  13. Python系列之heapq内置模块
  14. PHP实现跨域解决方法
  15. xss攻击和csrf攻击的定义及区别
  16. 在JavaScript中,如何判断数组是数组?
  17. DevExpress ASP.NET Core Controls 2019发展蓝图(No.1)
  18. Qt 添加 QtNetwork 库文件
  19. English trip -- VC(情景课)2 B Classroom objects
  20. URAL 1934 最短路变形

热门文章

  1. iOS开发-关闭/收起键盘方法总结
  2. MongoDB之索引
  3. seo-mask -- 为单页应用创建一个适合蜘蛛爬取的seo网站
  4. html-解决乱码问题
  5. mysql workbench 导出表结构
  6. eclipse 断点类别
  7. DataUml Design 教程4-代码生成
  8. Java Stream 官方文档翻译
  9. IOS设计模式浅析之外观模式(Facade)
  10. 为什么Servlet修改之后,Tomcat都得重启,servlet才会生效!