The C Programming Language Second Edition
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
The C Programming Language Second Edition的更多相关文章
- About learn《The C programming Language,Second Edition》
Today,My last week buy C language book arrived. Today,I week earnest study. No matter what difficult ...
- The C Programming Language (second edition) 实践代码(置于此以作备份)
1. #include <stdio.h> #include <stdlib.h> #include <math.h> #include<time.h> ...
- C: Answers to “The C programming language, Edition 2”
<The C programming language> Edition 2的习题答案地址: http://users.powernet.co.uk/eton/kandr2/index.h ...
- ESSENTIALS OF PROGRAMMING LANGUAGES (THIRD EDITION) :编程语言的本质 —— (一)
# Foreword> # 序 This book brings you face-to-face with the most fundamental idea in computer prog ...
- c++学习书籍推荐《The C++ Programming Language第四版》下载
百度云及其他网盘下载地址:点我 作者简介 Bjarne Stroustrup is the designer and original implementer of C++, the author o ...
- iOS Swift-元组tuples(The Swift Programming Language)
iOS Swift-元组tuples(The Swift Programming Language) 什么是元组? 元组(tuples)是把多个值组合成一个复合值,元组内的值可以使任意类型,并不要求是 ...
- iOS Swift-控制流(The Swift Programming Language)
iOS Swift-控制流(The Swift Programming Language) for-in 在Swift中for循环我们可以省略传统oc笨拙的条件和循环变量的括号,但是语句体的大括号使我 ...
- iOS Swift-简单值(The Swift Programming Language)
iOS Swift-简单值(The Swift Programming Language) 常量的声明:let 在不指定类型的情况下声明的类型和所初始化的类型相同. //没有指定类型,但是初始化的值为 ...
- Java Programming Language Enhancements
引用:Java Programming Language Enhancements Java Programming Language Enhancements Enhancements in Jav ...
随机推荐
- 用Volley-nullpointerexception
public Request(int method, String url, Response.ErrorListener listener) { mMethod = method; mUrl = u ...
- 页面找不到js方法的原因,关于EasyUI
有时EasyUI中datagride写法不正确,会导致无法加载页面上其他的js方法.datagride中的逗号是一个也不能多.一定要注意: 例如以下代码中标红的逗号就会导致后边的js不能正常加载. c ...
- Android AIDL Service 跨进程传递复杂数据
黑夜 黑夜给了我黑色的眼睛,我却用它寻找光明~ 传值方式 AIDL是同意跨进程传递值的,一般来说有三种方式: - 广播:这样的算是比較常见的一种方式了,传递小数据不错 - 文件:这个是保存到文件里.然 ...
- 使用maven结合requirejs管理前端脚本
已有的web项目,一直使用Maven做工程管理,现阶段前端调整为使用requirejs来负责模块加载依赖,同时使用jasmine来完成前端的UT. 便与在maven下统一管理,简单整理了下合在一起的使 ...
- android proguard 保留内部类
今天在使用Proguard keep一个 静态内部类的时候,混淆完之后一直找不到那个静态内部类,内心抓狂啊. 最后在stackoverflow上找到了答案: -keepattributes Excep ...
- python模块学习之logging
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中. filemode:文件打开方式,在指定了filename时使用这个 ...
- 推荐vim配置
"设置编码,处理中文乱码,文件默认utf8编码set fileencodings=utf-8,ucs-bom,cp936,big5 "设置默认配色方案colorscheme def ...
- hdu5800 To My Girlfriend dp 需要比较扎实的dp基础。
To My Girlfriend Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 第一百八十八节,jQuery,选项卡 UI
jQueryUI,选项卡 UI 学习要点: 1.使用 tabs 2.修改 tabs 样式 3.tabs()方法的属性 4.tabs()方法的事件 5.tabs 中使用 on 选项卡(tab),是一种能 ...
- 视频输出hdtv和sdtv
SDTV和HDTV人们分别把它们叫标准清晰度数字电视和高清晰度数字电视,SDTV电视节目很早在欧洲就开始广播,如,DVB-S(卫星数字视频广播).DVB-C(有线数字视频广播).DVB-T(地面数字视 ...