编译器对源代码的编译过程

对于C/C++源代码的编译,可以使用gcc(GNU Compiler Collection,GNU编译器集合)/g++进行编译。
gcc/g++分别是GNU的C/C++编译器,GNU是“GNU is Not Unix”的首字母缩写,GNU项目Richard Stallman在1983年9月27日公开发起的,GNU软件可以自由使用、复制、修改和发布,由此产生的GNU通用公共许可证(GNU General Public License,GPL)。
假设我们有一个源文件:hello_world.cpp(或者hello_world.c)。
我们知道,C/C++程序的执行分为四个步骤:
- 预处理
- 编译
- 汇编
- 链接

1.预处理阶段

例如:g++ -E hello_world.cpp -o hello_world.i
-o选项表示输出;使用-E选项,由预处理器cpp将源代码生成预处理.i文件。
预处理会展开以#开始的行,解释为预处理指令,包括:

(1). #include:头文件包含

#include <xxx.h>使用尖括号通常表示引用系统的标准库头文件,而且搜索路径也只在标准库路径;
#include "xxx.h"使用双引号通常表示引用自定义头文件,搜索路径是先在当前工程目录下搜索,搜索不到再到系统的标准库中搜索。

(2). 宏替换

无参数宏和带参数宏;多行宏(用\连接,\后面不能右空格);终止宏定义的作用域;宏替换(使用##,字符串替换)

#define PI 3.1415926    //无参数
#define MAX(A,B) ((A)>(B)?(A):(B))  //注意只作简单替换,不进行类型检查,所以对每一个参数加了括号
#define MIN(A,B)    \((A)<(B)?(A):(B))   //多行宏
#undef PI   //终止宏PI的定义
#define B(name) my_##_name   //B(first)替换为my_first_name

(3).条件编译指令

#if     //表达式为零对代码编译
#else
#elif
#ifndef //宏没有被定义就进行编译
#ifdef  //宏被定义就进行编译
#endif  //结束宏定义

例如:防御式头文件声明,防止重复引用:

#ifndef  XXX_H_
#define  XXX_H_
...
#endif  //XXX_H_

(4). 预定义的宏

__DATE__        //字符串常量,表示编译日期,形式:mm dd yyyy
__TIME__        //字符串常量,表示编译日期,形式:hh:mm:ss
__FILE__        //字符串常量,表示源文件(包含文件路径)
__FUNCTION__    //字符串常量,表示当前函数名
__LINE__        //整数常量,表示源文件行号

(5). 其它一些常见的预处理指令

#pragma once:保证头文件编译一次;
#Pragma pack(x):规定结构体/类等的对齐长度,x是一个数字

2.编译阶段

编译阶段由预处理器ccl将预处理.i文件转换为汇编代码.s文件,例如:

g++ -S hello_world.cpp -o hello_world.s

-S选项只激活了预处理和编译,从源文件.cpp到汇编文件.S

3. 汇编阶段

汇编阶段由汇编器as将汇编代码.S文件转化为机器代码.o文件,例如:

g++ -c hello_world.cpp -o hello_world.o

-c选项激活了预处理、编译和汇编,从源文件.cpp到目标机器文件.o

4. 链接阶段

链接阶段由链接器ld将机器代码.o文件连接生成可执行文件.exe/.out,例如:

g++ hello_world.o -o hello_world.out

链接的过程核心工作是解决各个模块间的符号(变量)相互引用的问题。
静态链接和动态链接:
- 静态链接
将函数代码直接拷贝到可执行程序中,如果多个程序调用同一个函数,内存中就会存在多个拷贝,不仅浪费了内存空间,还增大了可执行文件的体积。
- 动态链接
动态链接相比较于静态链接,并没有直接拷贝,只是在可执行文件中添加了一些重定位信息,当可执行文件真正执行时,动态链接库的内容才被映射到相应的进程,这时可执行文件根据定位信息找到相应的函数代码执行,这样节约了内存空间。

5. 编译器的一些默认操作

g++ -E hello_world.cpp      //没有生成.i文件,直接输出.i文件
g++ -E hello_world.cpp -o test.i
g++ -E hello_world.cpp > test.i     //正确的做法g++ -S hello_world.cpp  //默认生成hello_world.s
g++ -S hello_world.cpp -o hello_world.s     //等价g++ -c hello_world.cpp  //默认生成hello_world.o
g++ -c hello_world.cpp -o hello_world.o     //等价
g++ -c hello_world.s -o hello_world.o       //等价
g++ -c hello_world.i -o hello_world.o   //这个是错误的,不能对.i执行-c选项g++ hello_world.cpp     //默认直接生成a.out文件
g++ hello_world.cpp -o hello_world.out
g++ hello_world.o -o hello_world.out    //等价
g++ hello_world.s -o hello_world.out    //等价
g++ hello_world.i -o hello_world.out    //这个是错误的,不能对.i执行

常见的选项:

6. 告警提示

  • -pedantic选项:不符合ASNI/ISO C语言标准时告警。
  • -Wall选项:使编译器尽可能多产生告警信息。
  • -Werror选项:要求编译器对告警当作错误来处理,告警即停止编译。
  • -w选项:关闭告警信息。

程序告警有助于写出更加健壮的代码,以及有助于我们调式程序。

7.优化选项

-O0         //编译器不进行优化处理
-O/-O1      //编译器优化编译时间和可执行文件大小,缺省
-O2         //在-O1的基础上进一步优化
-O3         //在-O2的基础上进一步优化,包括inline函数

更加具体的请参考官方文档

gcc.pdf以及中文手册GCC_zh.htm。

编译器对源代码的编译过程相关推荐

  1. 编译器 LLVM Clang原理与实战 制作自己的编译器 source-to-source 源代码转换 编译遍 compile pass 代码插桩

    编译器 LLVM Clang原理与实战 参考1 clang LLVM CMU 教案 深入剖析-iOS-编译-Clang-LLVM LLVM_proj LLVM编程索引 llvm源码浏览带跳转 llvm ...

  2. 简述android源代码的编译过程,Android源码编译过程详述

    首先说一下,编译Android所用的系统,目前ubuntu是比较好的平台,也是官方推荐的,但具体版本,说的都比较少,为了避免大家走弯路,我 这里说一下,最好的就是ubuntu 8.10,他所带有的各个 ...

  3. 【gcc/g++】1.编译器, 编译过程和基本参数

    "木叶飞舞之处" 一, gcc编译器 二, gcc的编译过程 1--完整版 1. 预处理 2. 编译 3. 汇编 4. 链接: 2--简化版 简化编译过程 3--编译完成 三, g ...

  4. 66.javac 编译与 JIT 编译\编译过程\javac 编译\词法、语法分析\填充符号表\语义分析\字节码生成\JIT 编译

    66.javac 编译与 JIT 编译 66.1.编译过程 66.2.javac 编译 66.2.1.词法.语法分析 66.2.2.填充符号表 66.2.3.语义分析 66.2.4.字节码生成 66. ...

  5. Linux 程序编译过程的来龙去脉

    大家肯定都知道计算机程序设计语言通常分为机器语言.汇编语言和高级语言三类.高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类 ...

  6. Linux上C语言程序编译过程详解

    点击蓝字 关注我们 因公众号更改推送规则,请点"在看"并加"星标"第一时间获取精彩技术分享 来源于网络,侵删 本文将介绍如何将高层的C/C++语言编写的程序转换 ...

  7. RISC-V嵌入式开发准备篇1:编译过程简介

    原文出处:https://mp.weixin.qq.com/s/-syKN0DibKGGPCllaeNqMg 随着国内第一本RISC-V中文书籍<手把手教你设计CPU--RISC-V处理器篇&g ...

  8. GCC的编译过程以及其同盟成员和ELF文件的分析

    文章目录 一.GCC的同盟成员介绍 1.GCC的介绍 2.同盟成员之Binutils 3.同盟成员之C 运行库 二.GCC的详细编译过程 1.编译的简介 2.预处理(Preprocessing) 3. ...

  9. riscv的c语言编译,RiscV汇编介绍(1)-编译过程

    把高层的c/c++源文件转化为可执行文件的过程如下图所示(linux操作系统为例): 以hello.c程序为例,我们看下编译,汇编,链接到生产可执行文件的过程. 1.hello.c代码如下:#incl ...

  10. GCC编译器与编译过程

    文章目录 1.GCC简介 1.1概念 1.2 gcc与g++详解 1.2.1 .主要区别 1.2.2 后缀名相关 1.2.3 GCC参数 2 编译过程 2.1 预编译 2.2 编译 2.3汇编 2.4 ...

最新文章

  1. jquery 图片裁剪 java_[Java教程]5 款最新的 jQuery 图片裁剪插件
  2. heapq 对有序的数组列表进行整体排序
  3. 用特征迭代次数区分minst数据集的0和1
  4. android设置gradle位置,android studio gradle 位置更改
  5. C#线程通信与异步委托
  6. 强网杯Web部分review
  7. action在java_@Action(value=/login在java语句中是什么意思
  8. mysql markdown_mysql+数据库学习笔记(markdown)
  9. 【原创】matlab 2010的下载和安装
  10. 【ElementUI样式优化】el-input带自定义查询删除图标 ==> 图标点击可实现对应功能 ==> 一个input实现查询重置功能
  11. Linux系统入门学习
  12. 大数据学习——Hadoop本地模式搭建
  13. C#日历控件(MonthCalendar)
  14. 美国习惯用语flip out的中英文翻译解释和例子
  15. 借京东图文识别baseline 来看clip训练过程。 clip是怎样练成的 。
  16. #Paper reading#DeepInf: Social Influence Prediction with Deep Learning
  17. 学习笔记之——路径规划
  18. C语言假设银行一年存利
  19. crc-itu java实现_JAVA编程心得-JAVA实现CRC-CCITT(XMODEM)算法
  20. 用java实现基于感知器的数据线性分类

热门文章

  1. 用 Python 制作商品历史价格查询
  2. android 8.0 红米note3,红米Note3抢在小米6前面升到8.0,但是bug满天飞
  3. Linux第7章Gdk及Cairo基础,GNOME 平台的2D图形编程(GTK,GDK,Cairo...) 简介 [转]...
  4. 网络准入控制学习——Chap1
  5. Provision not found. A provision is required for deploying your app to the device. 解决方案
  6. 华为月薪11万招前端工程师,看到要求我傻眼了!
  7. MSP430F149串口收发程序详解
  8. 【30-60s计数器电路设计】数电课设
  9. mac 怎么抓取 iphone 手机 日志
  10. ImportError: No module named PyQt4.