C语言可执行文件生成过程
主要流程
主要流程包括:
预处理->编译->汇编->链接
- 预处理:源代码.c文件——>.i文件
处理#开头的代码,加载头文件、宏替换、条件编译等
- 编译:.i文件——>.s文件(汇编代码)
- 汇编:.s文件——>.o(.obj)文件(机器代码)
- 链接:.o文件——>.out 可执行文件
编译过程的作用:目标文件和可执行文件格式相同都是二进制代码,但是只完成了编写部分代码的二进制转换,执行程序还需要将目标文件和系统组件(包括标准库和动态链接库能)结合。执行的位置可以是在编译时、程序加载时或者执行过程中。
Gcc优化
- -O0:无优化(默认)。
- -O1:使用能减少目标文件大小以及执行时间并且不会使编译时间明显增加的优化.在编译大型程序的时候会显著增加编译时内存的使用。
- -O2: 包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化.编译器不执行循环展开以及函数内联.此选项将增加编译时间和目标文件的执行性能。(一般优化到-O2就可以了)
- -Os:专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项.并且执行专门减小目标文件大小的优化选项。
- -O3: 打开所有-O2的优化选项并且增加 -finline-functions, -funswitch-loops,-fpredictive-commoning, -fgcse-after-reload and -ftree-vectorize优化选项。
优化效果实例:
gcc在编译的时候可以使用-O、-O2和-O3选项(字母O要大写)来对代码进行优化,以下是一个故意创建的代码欧用于配合time命令测试该优化选项的效果,time命令的输出为real、user和sys三项,各个部分说明如下:
real:进程总的执行时间, 它和系统负载有关(包括了进程调度,切换的时间),
user:被测量的进程中用户指令的执行时间;
sys:被测量进程中内核代用户指令执行的时间,user和sys的和被称为CPU时间。
user:被测量的进程中用户指令的执行时间;
sys:被测量进程中内核代用户指令执行的时间,user和sys的和被称为CPU时间。
#include <stdio.h> int main(void) { unsigned long int counter; /*定义相关的变量*/ unsigned long int result; int i; unsigned long int temp; unsigned int five; /*判断条件在每一次for循环时都会进行一次计算*/ for (counter=0; counter < 2009 * 2009 * 100 / 4 + 2010; counter += (10 - 6) / 4) { temp=counter / 1979; for(i=0; i < 20; i++) { five=200*200/8000; /*每一次for循环都会进行复杂的计算*/ } result=counter; } printf("Result is %ld\n", result); return 0; }
输入以下代码查看三种不同的编译选项对应的执行时间差异(不同的机器有不同的差别,相同的机器在同时运行不同的其他程序的时候也有差异)
alloy@raspberrypi:~/linuxcupdate/chapter4$ gcc inefficient.c -o inefficient alloy@raspberrypi:~/linuxcupdate/chapter4$ time ./inefficient alloy@raspberrypi:~/linuxcupdate/chapter4$ gcc -O2 inefficient.c -o inefficient alloy@raspberrypi:~/linuxcupdate/chapter4$ time ./inefficient alloy@raspberrypi:~/linuxcupdate/chapter4$ gcc -O3 inefficient.c -o inefficient alloy@raspberrypi:~/linuxcupdate/chapter4$ time ./inefficient