c语言的编译过程详解
c语言的编译过程详解
IDE的使用让很多和我一样的人对C/C++可执行程序的底层生成一知半解,不利于我们深入理解原理。在这里小结一下,望路过的大神指正~
前言:从一个源文件(.c文件)到可执行程序到底经历了哪几步,我想很多人都知道,但是每一步具体做了什么,估计很多像我一样的人就不能说的清清楚楚,明明白白了。
C语言编译过程分成四个步骤:
1,由.c文件到.i文件,这个过程叫预处理
2,由.i文件到.s文件,这个过程叫编译
3,由.s文件到.o文件,这个过程叫汇编
4,由.o文件到可执行文件,这个过程叫链接
编辑一个小程序,hello.c
#include <stdio.h>
#include <stdlib.h>
int main()
{printf("hello world!\n");
return 0;
}
1、预处理
预处理过程实际上是处理“#”的过程:#include包含的头文件直接拷贝到hello.c中;#define定义的宏定义进行替换,同时删除代码中没有的注释部分…
具体做的事儿如下:
(1)将所有的#define删除,并且展开所有的宏定义。说白了就是字符替换
(2)处理所有的条件编译指令,#ifdef #ifndef #endif等,就是带#的那些
(3)处理#include,将#include指向的文件插入到该行处
(4)删除所有注释
(5)添加行号和文件标示,这样的在调试和编译出错的时候才知道是是哪个文件的哪一行
(6)保留#pragma编译器指令,因为编译器需要使用
gcc -E hello.c -o a.c 可以生成预处理以后的文件,通过查看文件内容和文件大小可以得知a.c将stdio.h和stdlib.h包含了进来。一下是在Ubuntu上编译后的文件:
drwxrwxr-x 2 lpq lpq 4096 1月 10 10:21 ./
drwxrwxr-x 4 lpq lpq 4096 1月 10 10:19 ../
-rw-rw-r-- 1 lpq lpq 42194 1月 10 10:21 a.c
-rw-rw-r-- 1 lpq lpq 95 1月 10 10:21 hello.c
2、编译
编译的过程实质上是将高级语言翻译成机器语言的过程,即对a.c做了这些事:
(1)词法分析
(2)语法分析
(3)语义分析
(4)优化后生成相应的汇编代码
注:高级语言——>汇编语言——>机器语言(二进制)
gcc -S hello.c -o a.s 可以生成汇编代码,汇编代码如下:
.file "hello.c"2 .section .rodata3 .LC0:4 .string "hello world!"5 .text6 .globl main7 .type main, @function8 main:9 .LFB0:
10 .cfi_startproc
11 pushl %ebp
12 .cfi_def_cfa_offset 8
13 .cfi_offset 5, -8
14 movl %esp, %ebp
15 .cfi_def_cfa_register 5
16 andl $-16, %esp
17 subl $16, %esp
18 movl $.LC0, (%esp)
19 call puts
20 movl $0, %eax
21 leave
22 .cfi_restore 5
23 .cfi_def_cfa 4, 4
24 ret
25 .cfi_endproc
26 .LFE0:
27 .size main, .-main
28 .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
29 .section .note.GNU-stack,"",@progbits
3、汇编
gcc -c hello.c -o a.o 是将源文件翻译成二进制文件,类Unix系统编译的结果生成.o文件,Windows系统生成的是.obj文件。
所以,编译过程就是讲.c文件翻译成二进制文件。
汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
由于a.o是机器码,不能以纯文本的形式打开(vim打开是乱码的)。
4、链接
就像hello.c中使用到了C标准库的东西“printf”,但是编译过程只是将源文件翻译成二进制文件而已,这个二进制文件还不能直接执行,还需要一个动作:将翻译成的二进制文件与需要用到的库绑定在一块。
gcc hello.c -o a.out 可以生成可执行程序,即gcc不带任何参数。ldd命令可以查看你的可执行程序所依赖的库。
可以看到a.o的大小是1.1k,毕竟他只是把源文件翻译成二进制文件。a却有7k,应该是他多了很多“绳子”吧。在运行的时候这些“绳子”就将对应的库函数“牵过来”。很形象的比喻是不是?哈哈。libc.so.6 中就对咱们用的printf进行了定义。
补充:
编译过程可分为6步:扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成、目标代码优化。
词法分析:扫描器(Scanner)将源代的字符序列分割成一系列的记号(Token)。lex工具可实现词法扫描。
语法分析:语法分析器将记号(Token)产生语法树(Syntax Tree)。yacc工具可实现语法分析(yacc: Yet Another Compiler Compiler)。
语义分析:静态语义(在编译器可以确定的语义)、动态语义(只能在运行期才能确定的语义)。
源代码优化:源代码优化器(Source Code Optimizer),将整个语法书转化为中间代码(Intermediate Code)(中间代码是与目标机器和运行环境无关的)。中间代码使得编译器被分为前端和后端。编译器前端负责产生机器无关的中间代码;编译器后端将中间代码转化为目标机器代码。
目标代码生成:代码生成器(Code Generator).
目标代码优化:目标代码优化器(Target Code Optimizer)。
链接的主要内容是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确地衔接。
链接的主要过程包括:地址和空间分配(Address and Storage Allocation),符号决议(Symbol Resolution),重定位(Relocation)等。
链接分为静态链接和动态链接。
静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行文件会比较大。
而动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去。
c语言的编译过程详解相关推荐
- Linux上C语言程序编译过程详解
点击蓝字 关注我们 因公众号更改推送规则,请点"在看"并加"星标"第一时间获取精彩技术分享 来源于网络,侵删 本文将介绍如何将高层的C/C++语言编写的程序转换 ...
- Android编译过程详解(三)
Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359.html Android编译过程详解(二):h ...
- uboot配置和编译过程详解
▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ 分享一个大神朋友的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到 ...
- 2.4.U-Boot配置和编译过程详解-U-Boot和系统移植第4部分视频课程笔记
目录 2.uboot 主Makefile分析 2.1.Makefile 分析2 2.2.Makefile 分析3 2.3.Makefile 分析4 2.4.链接脚本的定义 2.5.指定链接地址 如果T ...
- c语言编译过程详解,预处理,编译,汇编,链接(干货满满)
楔子 我们在各自的电脑上写下代码,得明白我们代码究竟是如何产生的,不想了解1,0什么的,但这几个环节必须掌握吧. 我们的代码会经过这4个环节,从而形成最终文件,c语言作为编译语言,用来向计算机发出指令 ...
- C C++的编译过程详解
C/C++编译过程 C/C++编译过程主要分为4个过程 1) 编译预处理 2) 编译.优化阶段 3) 汇编过程 4) 链接程序 一.编译预处理 (1)宏定义指令,如#define Name Token ...
- C/C++程序编译过程详解
C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作 ...
- WinCE系统的编译过程详解
在WinCE系统中,当我们完成了相关的开发和系统定制工作以后,会编译WinCE系统,最后生成NK.bin和NK.nb0.下面介绍一下WinCE系统的编译过程,大致分为4个阶段:编译阶段(Compile ...
- linux下gcc的编译过程详解
Linux系统下的Gcc(GNU C Compiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作品之一.gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一 ...
最新文章
- mybatis关联查询
- 【渝粤教育】国家开放大学2018年春季 7394-22T政府公共关系 参考试题
- flask jinja2 如何遍历新闻列表
- SpringBoot + Shiro 缓存记住密码
- python os.path.split_Python中split()和os.path.split()
- php 使用json 教程,如何在php中正确的使用json_PHP
- 返回两个时间范围内的一个随机时间
- 简单实用的微信缓存框架mmkv
- 恋物志(二):独居者的智能生活指南
- 索尼笔记本E系列,关闭触摸板
- mac安装texstudio+mactex(texlive)2022+中文字体
- ArrayList 和 Vector 的区别
- 如何使用阿里云字体图标教程
- 公交卡管理系统C语言,关于NFC不能刷公交卡的研究(暂无方法)
- 构建U盘启动的嵌入式linux
- 【迷人的爪哇】—Java数据类型和变量
- [转]数学之美-【算法】 - 用来流方式计算UV的基数算法
- 第三章 人类社会及其发展规律
- 数据分析包的比较:R,Matlab,SciPy,Excel,SAS,SPSS,Stata
- python爬取去哪儿网酒店信息
热门文章
- Mac下PDF转EPS的方法
- 中大轻纺城源代码Android,中大最全找面料攻略
- 为什么c语言程序无法生成,程序无法生成
- FBE 加密手机修改密码最后点确定时,马上拔电池掉电出现开机进入recovery
- GMOJ - 2021.07.20【普及组】模拟赛C组 - 排座椅(seat)、传球游戏(ball)、立体图(drawing)、间谍派遣、seek
- CF1657D:D. For Gamers. By Gamers.(dp,调和级数,二分)
- Java面试题总结(三)
- 6、流程控制(重点)
- wps批量调整图片大小
- Mysql复习笔记(day02 SQL)