转载文章:http://www.franktly.com

前言


GNU CC(简称Gcc)是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object- C等语言编写的程序。Gcc不仅功能强大,而且可以编译如C、C++、Object C、Java等多种语言,而且Gcc又是一个交叉平台编译器,它能够在当前CPU平台上为多种不同体系结构的硬件平台开发软件。本章中的示例均采用Gcc版本为4.8.2。

Gcc编译链接流程


Gcc编译链接流程分为四个步骤:

  1. 预处理(Pre-Processsing)
  2. 编译(Compiling)
  3. 汇编(Assembling)
  4. 链接(Linking)

Gcc指令的一般格式为:

gcc [option1] compile-files [option2] object-files

其中目标文件可缺省,Gcc默认生成的可执行文件命名为:编译文件名.out

下面以简单的hello world程序为例说明Gcc编译的四个过程:

1
2
3
4
5
6
#include <stdio.h>
void main(int argc, char* argv[])
{
printf("hello world");
return;
}

预处理过程

option1 为-E,生成的目标文件为.i(c)或.ii(c++)后缀的经过预处理的编译输入文件,Gcc指令为:

tly@ubuntu ~> gcc -E test.c -o test.i

生成的预编译文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1 "test.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 374 "/usr/include/features.h" 3 4
# 1 "/usr/include/i386-linux-gnu/sys/cdefs.h" 1 3 4
... 省略
...
extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
# 913 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 943 "/usr/include/stdio.h" 3 4
# 2 "test.c" 2
void main(int argc, char* argv[])
{
printf("hello world");
return;
}

Gcc预处理过程把<stdio.h>的内容插入到hello.i文件中了

编译

option1 为-S,生成的目标文件为.s.S后缀的经过编译但是没有汇编过的汇编文件,Gcc编译过程首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,Gcc把代码翻译成汇编语言Gcc指令为:

tly@ubuntu ~> gcc -S test.i -o test.s

生成的编译之后的汇编文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.file "test.c"
.section .rodata
.LC0:
.string "hello world"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call printf
nop
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
~

Gcc编译过程已经将其转化为汇编语言了

汇编

option1 为-c,生成的目标文件为以.o为后缀的二进制目标代码文件,Gcc指令为:

tly@ubuntu ~> gcc -c test.s -o test.o

生成的汇编之后的目标文件内容为:

1
2
3
^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^A^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@^X^A^@^@^@^@^@^@4^@^@^@^@^@(^@^M^@
^@U<89>å<83>äð<83>ì^PÇ^D$^@^@^@^@èüÿÿÿ<90>ÉÃhello world^@^@GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2^@^@^@^@^T^@^@^@^@^@^@^@^AzR^@^A|^H^A^[^L^D^D<88>^A^@^@^\^@^@^@^\^@^@^@^@^@^@^@^X^@^@^@^@A^N^H<85>^BB^M^ETÅ^L^D^D^@^@^@.symtab^@.strtab^@.shstrtab^@.rel.text^@.data^@.bss^@.rodata^@.comment^@.note.GNU-stack^@.rel.eh_frame^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^_^@^@^@^A^@^@^@^F^@^@^@^@^@^@^@4^@^@^@^X^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^[^@^@^@ ^@^@^@^@^@^@^@^@^@^@^@ä^C^@^@^P^@^@^@^K^@^@^@^A^@^@^@^D^@^@^@^H^@^@^@%^@^@^@^A^@^@^@^C^@^@^@^@^@^@^@L^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@+^@^@^@^H^@^@^@^C^@^@^@^@^@^@^@L^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@0^@^@^@^A^@^@^@^B^@^@^@^@^@^@^@L^@^@^@^L^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@8^@^@^@^A^@^@^@0^@^@^@^@^@^@^@X^@^@^@%^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^A^@^@^@A^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@}^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@U^@^@^@^A^@^@^@^B^@^@^@^@^@^@^@<80>^@^@^@8^@^@^@^@^@^@^@^@^@^@^@^D^@^@^@^@^@^@^@Q^@^@^@ ^@^@^@^@^@^@^@^@^@^@^@ô^C^@^@^H^@^@^@^K^@^@^@^H^@^@^@^D^@^@^@^H^@^@^@^Q^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@¸^@^@^@_^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^A^@^@^@^B^@^@^@^@^@^@^@^@^@^@^@ ^C^@^@°^@^@^@^L^@^@^@ ^@^@^@^D^@^@^@^P^@^@^@ ^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@Ð^C^@^@^T^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^D^@ñÿ^@^@^@^@^@^@^@^@^@^@^@^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^D^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^E^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^G^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^H^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^F^@^H^@^@^@^@^@^@^@^X^@^@^@^R^@^A^@^M^@^@^@^@^@^@^@^@^@^@^@^P^@^@^@^@test.c^@main^@printf^@^L^@^@^@^A^E^@^@^Q^@^@^@^B
^@^@ ^@^@^@^B^B^@^@

Gcc汇编成的.o目标文件是乱码,不过可以通过nm命令查看其符号表:

tly@ubuntu ~> nm test.o
00000000 T mainU printf

链接

在成功编译之后,就进入了链接阶段,这个hello world小程序的链接过程主要是查找包含的stdio.h头文件的printf()函数的实现(因为stdio.h头文件只包含函数声明),这个函数实现是在libc.so.6的库文件中。在没有特别指定时,Gcc会到系统默认的搜索路径/usr/lib下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数printf()了,而这也就是链接的作用。

函数库一般分为静态库动态库两种。
静态库:是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为.a(linux)或.lib(windows)。
动态库: 与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般为.so(linux)或.dll(windows),如前面所述的libc.so.6就是动态库。
Gcc在编译时默认使用动态库

当然,也可以一次性使用-c选项,直接生成目标文件test.o,Gcc指令为:

tly@ubuntu ~> gcc -c test.c -o test.o

完成了链接之后,Gcc就可以生成可执行文件test,Gcc指令为:

tly@ubuntu ~> gcc test.o -o test

运行该可执行文件test

tly@ubuntu ~> ./test
hello world⏎

Gcc编译选项分析

Gcc有超过100个的可用选项,一般主要包括以下五种类型选项:

  1. 总体选项
  2. 告警和出错选项
  3. 优化选项
  4. 体系结构相关选项

总体选项


选项名 选项意义
-E 只是编译不汇编,生成汇编代码.s
-S 只进行预编译生成.i,不做其他处理
-c 只是编译不链接,生成目标文件.o
-g 在可执行程序中包含标准调试信息
-o file 把输出文件输出到file里
-v 打印出编译器内部编译各过程的命令行信息和编译器的版本
-I dir 在头文件的搜索路径列表中添加dir目录
-L dir 在库文件的搜索路径列表中添加dir目录
-static 链接静态库
-llibrary 链接名为library的库文件库

对于-I dir选项可在头文件的搜索路径列表中添加dir目录。由于Linux中头文件都默认放到了/usr/include/目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过-I dir选项来指定(-L dir类似),这样,Gcc就会到相应的位置查找对应的目录
<>表示在标准路径中搜索头文件,“ ”表示在本目录中搜索,如果把自定义的头文件#include<my.h>改为#include “my.h”,就不需要加上“-I”选项了
-I dir-L dir都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名

对于-llibrary选项,省去了前缀lib,它实际上是指示Gcc去连接库文件liblibrary.so。由于在Linux下的库文件命名时有一个规定:必须以lib三个字母开头。因此在用-l选项指定链接的库文件名时可以省去lib三个字母。也就是说Gcc在对-llibrary进行处理时,会自动去链接名为liblibrary.so的文件

告警和出错选项


选项名 选项意义
-ansi 支持符合ANSI标准的C程序
-pedantic 允许发出ANSI C标准所列的全部警告信息
-pedantic-error 允许发出ANSI C标准所列的全部错误信息
-w 关闭所有告警
-Wall 允许发出Gcc提供的所有有用的报警信息

修改上述的helloworld测试程序为:

1
2
3
4
5
6
7
#include <stdio.h>
void main(int argc, char* argv[])
{
long long tmp; // 增加非ANSI-C类型long long 未使用的临时变量tmp
printf("hello world");
return 0; // 返回错误类型int
}

1.默认无告警和出错选项情况:

tly@ubuntu ~> gcc -c test.c -o test.o
test.c: In function ‘main’:
test.c:6:3: warning: ‘return’ with a value, in function returning void [enabled by default]return 0;^

只识别了main的错误返回类型int

2.增加-ansi选项情况:

tly@ubuntu ~> gcc -c test.c -o test.o -ansi
test.c: In function ‘main’:
test.c:6:3: warning: ‘return’ with a value, in function returning void [enabled by default]return 0;^

只识别了main的错误返回类型int

3.增加-pedantic选项情况:

tly@ubuntu ~> gcc -c test.c -o test.o -pedantic
test.c:2:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]void main(int argc, char* argv[])^
test.c: In function ‘main’:
test.c:4:8: warning: ISO C90 does not support ‘long long’ [-Wlong-long]long long tmp;^
test.c:6:3: warning: ‘return’ with a value, in function returning void [enabled by default]return 0;^

识别了main的错误返回类型int 和 long long 非 ISO C90 支持类型

4.增加-pedantic-errors选项情况:

tly@ubuntu ~> gcc -c test.c -o test.o -pedantic-errors
test.c:2:6: error: return type of ‘main’ is not ‘int’ [-Wmain]void main(int argc, char* argv[])^
test.c: In function ‘main’:
test.c:4:8: error: ISO C90 does not support ‘long long’ [-Wlong-long]long long tmp;^
test.c:6:3: error: ‘return’ with a value, in function returning voidreturn 0;^

识别了main的错误返回类型int 和 long long 非 ISO C90 支持类型

5.增加-w选项情况:

tly@ubuntu ~> gcc -c test.c -o test.o -w

屏蔽了告警和出错信息

6.增加-Wall选项情况:

tly@ubuntu ~> gcc -c test.c -o test.o -Wall
test.c:2:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]void main(int argc, char* argv[])^
test.c: In function ‘main’:
test.c:6:3: warning: ‘return’ with a value, in function returning void [enabled by default]return 0;^
test.c:4:13: warning: unused variable ‘tmp’ [-Wunused-variable]long long tmp;^

识别了main的错误返回类型int 和临时变量tmp未使用的告警信息

优化选项


选项名 选项意义
-On n是一个代表优化级别的整数,典型的范围是从0变化到2或3

不同的优化级别对应不同的优化处理工作。
-O 提供基础级别的优化
-O2 提供更加高级的代码优化,会占用更长的编译时间
-O3 提供最高级的代码优化
进行调试的时候,最好关闭编译优化,否则程序自动优化,执行的步骤可能有变化

体系结构相关选项


选项名 选项意义
-mcpu=type 对不同的CPU使用相应的CPU指令。可选择的有i386、i486、pentium等
-mieee-fp 使用IEEE标准进行浮点数的比较
-mno-ieee-fp 不使用IEEE标准进行浮点数的比较
-msoft-float 输出包含浮点库调用的目标代码
-mshort 把int类型作为16位处理,相当于short int
-mrtd 将函数参数个数固定的函数用ret NUM返回,节省调用函数的一条指令
福利答谢大家!
感谢您阅读本篇文章,对此特别发放一个无门槛的现金红包,打开支付宝扫码领取,可以领到钱的哦!

Gcc编译链接及常用选项总结相关推荐

  1. gcc编译命令的常用选项——强烈推荐大家使用 -Wall 选项

    C程序编编译的过程分为如下四个阶段 1.预处理:头文件展开(#include).宏替换(#define).条件编译(#ifdef)(.i)使用预处理器(预处理阶段处理的都是以#开头的代码) 2.编译: ...

  2. gcc/g++ 命令的常用选项

    gcc/g++ 命令的常用选项 使用g++编译CPP文件如果用gcc编译C++源文件时,加以下选项:-lstdc++,否则使用了C++操作的文件编译会出错.假如在程序中用到new delete操作,而 ...

  3. 使用gcc编译和链接C语言程序,用GCC编译链接程序--编译链接器GCC常用功能(菜鸟级)...

    转载自:http://daimajishu.iteye.com/blog/1089740 对gcc认识的一篇文章,就转载了,截取了自己感兴趣部分. 一,GCC编译器简介 虽然我们称Gcc是C语言的编译 ...

  4. GCC 编译链接命令用法

    Contents 一.简介... 2 二.简单编译... 2 2.1预处理... 2 2.2编译为汇编代码(Compilation). 3 2.3汇编(Assembly). 3 2.4连接(Linki ...

  5. gcc编译c文件常用命令参数解释

    gcc编译c文件 gcc是常用来编译c语言程序的编译器,了解它编译c语言的命令参数,对c/c++语言的学习是有一定好处的. gcc编译文件一步到位的命令格式 gcc main.c -o main.ex ...

  6. gcc编译链接动态库

    文章目录 前言 操作步骤 1.直接生成目标so文件 2.先生成.o中间文件再链接成目标so文件 总结 前言 以下内容主要作为学习记录,有不准确的地方希望帮忙指出来,谢谢 以下是本篇文章正文内容,下面示 ...

  7. gcc编译链接头文件和库文件

    GCC与头文件 gcc -参数: -I ( i 的大写) :指定头文件路径(相对路径或绝对路径,建议相对路径) -i :指定头文件名字 (一般不使用,而是直接放在**.c 文件中通过#include& ...

  8. Linux环境下gcc编译链接库-lz -lrt -lm -lc都是什么库?

    编译链接库:-lz -lrt -lm -lc都是什么库 -lz      压缩库(Z) -lrt     实时库(real time):shm_open系列 -lm     数学库(math) -lc ...

  9. Linux GCC 编译过程分析及常用检错的编译选项

    文章目录 简介 一.拆解编译过程 1.准备源程序 2.分析拆解过程 3. 多个程序文件的编译 4.检错的编译选项 1.-pedantic 编译选项 2.-Wall 编译选项 3.-Werror 编译选 ...

最新文章

  1. DWZ(J-UI)selectedToDo操作完成后刷新Tab
  2. C# 去除文件和文件夹的只读属性
  3. 启帆工业机器人综合收入如何_发那科工业机器人ROBOGUIDE如何更方便的查看机器人报警日志...
  4. 12 款 Linux 终端推荐
  5. SAP OData实现错误消息:OPPORTUNITIES_GET_ENTITY not implemented in data provider class
  6. 理解UI线程——SWT, Android, 和Swing的UI机理
  7. 如何检测C语言中的内存漏洞(leak)?
  8. 挖掘城市ip_抖in杭州嘉年华,原来城市营销还能这么玩!
  9. Jenkins配置MSBuild时使用环境变量
  10. php正则表达式叹号,js库前加一个感叹号(!)是什么意思??
  11. 无任何网络提供程序接受指定的网络路径
  12. STM32 ADC没有输入电压时,采集结果不为0
  13. 如何不显示index.php,tp如何隐藏index.php
  14. 要么放权,要么输得起 | 卫哲谈战略
  15. 数据类型选方法【SPSS 073期】
  16. native2ascii转译HTML字符,native2ascii转字符
  17. SQL安装步骤及可能遇到的错误
  18. JS逆向解析案例-巨潮证券市场数据库(python)
  19. numpy取数组中的行和列
  20. 数据共享交换平台解决方案

热门文章

  1. iOS 地图定位 定位
  2. 从0到1学习Vue.js,包含例子及实战项目(三)
  3. 使用类计算矩形的面积
  4. elasticsearch 集群no known master node
  5. JAVA基础知识(2)--队列的操作
  6. OSPF网络类型详解
  7. placement new 操作符
  8. struts2 文件上传与下载 (初始文件上传的底层技术)——struts2第七讲
  9. nyoj904 search
  10. C++ 类型转换(强制类型转换)