C/C++程序编译运行过程
Posted C语言编程开发
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++程序编译运行过程相关的知识,希望对你有一定的参考价值。
简单来说,整个过程分为四个阶段:预处理(Pre-Processing)、编译(Compilation)、汇编(Assembling)、链接(Linking)。
注意:其中源程序、修改了的源程序和汇编程序都是文本文件,而可重定位目标程序和可执行目标程序都是二进制文件。
似乎到这里就该结束了,因为整个过程已经讲完了?。当然如果只是这样介绍的话本文就没有存在的价值了,我们还得再深入一点分别讲解这四个阶段?。
预处理
首先我们准备一个简单的Hello World程序,命名为main.c。
#include<stdio.h>
#defineinfo "Hello, world "intmain(){// A simple program.printf(info);return0;}
预处理阶段做的事情就是预处理器(cpp)根据以字符#开头的代码修改原始的C程序。
比如#include <stdio.h>,将头文件stdio.h中的内容加到程序文本中
比如#define info "Hello, world ",会将宏定义的info替换成字符串“Hello, world ”(当然我这里只是为了举例,一般我们不这么写)
此外,会将注释比如// A simple program.删除
预处理是直接对源文件进行处理(不关注语法规则), 然后得到另一个C程序,通常以.i作为文件扩展名。
我们可以在Linux系统(我这里用的是Ubuntu)下直接使用gcc -E main.c -o main.i命令得到预处理后的C程序main.i。我截取了一部分(总共有800+行),可以很明显的看到:引入了头文件,info被替换了,注释没了,还添加了一些特殊的标记,告诉编译器每行的来源,以便它可以使用它们来产生合理的错误消息。
#1"main.c"#1"<built-in>"#1"<command-line>"#31"<command-line>"#1"/usr/include/stdc-predef.h"134............externvoidfunlockfile(FILE*__stream)__attribute__((__nothrow__,__leaf__));#868"/usr/include/stdio.h"34#2"main.c"2#3"main.c"intmain(){printf("Hello, world ");return0;}
编译
编译阶段做的事情就是编译器(cc1)将C程序main.i翻译成汇编语言程序main.s。
检查C程序的语法错误
将文件翻译成中间代码,即汇编语言
可选地优化翻译后的中间代码,获得更好的性能
我们可以使用gcc -S main.i -o main.s得到翻译后的汇编程序main.s,截取部分如下。
.file"main.c".text.LC0:.string"Hello, world".text.globl mainmain:.LFB0:.cfi_startproc pushq%rbp movq%rsp,%rbp.......LFE0:.size main,.-main.ident"GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0".section.note.GNU-stack,"",@progbits
其中的语句比如pushq %rbp描述了一条低级机器语言指令。汇编语言是有用的,它为不同高级语言的不同汇编器提供了通用的输出语言,C汇编器和Fortran汇编器产生的输出文件都是一样的汇编语言。
汇编
汇编阶段做的事情就是汇编器(as)将main.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件main.o(Windows下为xx.obj而Linux下为xx.o)中。main.o是一个二进制文件,如果我们使用文本编辑器打开main.o,会看到一堆乱码。
我们可以使用gcc -c main.s -o main.o得到可重定位目标程序main.o,如下所示。
LF>?@@UH䈍=距ello,worldGCC:(Ubuntu7.3.0-27ubuntu1~18.04)7.3.0zRx#main.cmain_GLOBAL_OFFSET_TABLE_puts?ÿÿ C ??ÿÿ.symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.rela.eh_frame @0&90d+BWR@@
不出所料的一堆乱码?。
链接
我们的main.c程序中使用了printf函数,printf函数是每个C编译器都提供的标准C库中的一个函数,它存在于一个名为printf.o的单独预编译好了的目标文件中。
链接阶段做的事情就是链接器(ld)将需要用到的目标文件比如main.o和printf.o进行合并,并生成一个可执行(目标)文件,可以被加载到内存中,由系统执行。
实际上我们直接执行gcc main.c -o main命令得到的就是可执行文件,Windows下为.exe,Linux下默认为具有可执行权限的a.out,当然我们使用了-o来自定义输出文件名。
以上就是整个编译执行过程。
另外如果你想更好的提升你的编程能力,学好C语言C++编程!弯道超车,快人一步!笔者这里或许可以帮到你~
UP在主页上传了一些学习C/C++编程的视频教程,有兴趣或者正在学习的小伙伴一定要去看一看哦!会对你有帮助的~
分享(源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
免费学习书籍:
免费学习资料:
以上是关于C/C++程序编译运行过程的主要内容,如果未能解决你的问题,请参考以下文章