gcc/g++

编译器 gcc/g++

背景知识

编译过程分为四个阶段:

阶段 说明
1. 预处理 进行宏替换、去注释、条件编译、头文件展开等
2. 编译 生成汇编代码
3. 汇编 生成机器可识别代码(目标文件)
4. 链接 生成可执行文件或库文件

gcc 编译选项

基本格式

bash 复制代码
gcc [选项] 要编译的文件 [选项] [目标文件]

预处理(进行宏替换)

  • 功能:宏定义、文件包含、条件编译、去注释等
  • 说明 :预处理指令是以 # 号开头的代码行
  • 选项-E(让 gcc 在预处理结束后停止编译过程)
  • 输出文件.i 文件(已经过预处理的 C 原始程序)

示例

bash 复制代码
gcc -E hello.c -o hello.i

编译(生成汇编)

  • 功能:检查代码规范性和语法错误,将代码翻译成汇编语言
  • 选项-S(只进行编译而不进行汇编,生成汇编代码)
  • 输出文件.s 文件(汇编代码)

示例

bash 复制代码
gcc -S hello.i -o hello.s

汇编(生成机器可识别代码)

  • 功能 :将 .s 汇编文件转成目标文件(二进制目标代码)
  • 选项-c
  • 输出文件.o 文件(目标文件)

示例

bash 复制代码
gcc -c hello.s -o hello.o

链接(生成可执行文件或库文件)

  • 功能:将目标文件链接成可执行程序
  • 说明:成功编译后进入链接阶段

示例

bash 复制代码
gcc hello.o -o hello

动态链接和静态链接

在实际开发中,多个源文件之间存在依赖关系。每个 .c 文件独立编译成 .o 文件,为了满足依赖关系,需要将这些目标文件进行链接,形成可执行程序。

静态链接

缺点

  • 浪费空间 :多个程序对同一个目标文件有依赖时,每个可执行程序都含有一份副本(如多个程序都调用 printf(),则每个程序都包含 printf.o
  • 更新困难:库函数代码修改后,需要重新编译链接形成可执行程序

优点

  • 可执行程序中已具备所有执行所需的内容
  • 运行时速度快

动态链接

动态链接把程序按模块拆分成相对独立的部分,在程序运行时才将它们链接在一起,而不是像静态链接那样把所有模块都链接成一个单独的可执行文件。

查看可执行程序依赖的动态库

bash 复制代码
$ ldd hello
linux-vdso.so.1 => (0x00007fffeb1ab000)
libc.so.6 => /lib64/libc.so.6 (0x00007ff776af5000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff776ec3000)

ldd 命令用于打印程序或者库文件所依赖的共享库列表。

库的概念

C 程序中的 printf 函数并没有在代码中定义实现,stdio.h 中也只有声明。实际实现被放在 libc.so.6 库文件中

在没有特别指定时,gcc 会到系统默认搜索路径 /usr/lib 下进行查找,链接到 libc.so.6 库函数,从而实现 printf 函数------这就是链接的作用。


静态库和动态库

类型 说明 后缀名 链接时机
静态库 编译链接时,把库文件的代码全部加入到可执行文件中,运行时不再需要库文件 .a 编译时
动态库 编译链接时不加入代码,程序执行时由运行时链接文件加载库 .so 运行时

注意事项

  • gcc 在编译时默认使用动态库
  • 可以使用 file 命令验证生成的二进制程序是否为动态链接

示例

bash 复制代码
gcc hello.o -o hello   # 默认动态链接

gcc 其他常用选项(了解即可)

选项 说明
-E 只激活预处理,不生成文件,需要重定向到输出文件
-S 编译到汇编语言,不进行汇编和链接
-c 编译到目标代码(.o 文件)
-o 文件输出到指定文件
-static 对生成的文件采用静态链接
-g 生成调试信息,GNU 调试器(gdb)可利用该信息
-shared 尽量使用动态库,生成文件较小,但需要系统提供动态库
-O0 优化级别 0:不进行优化
-O1 优化级别 1:缺省值(默认级别)
-O2 优化级别 2
-O3 优化级别 3:优化级别最高
-w 不生成任何警告信息
-Wall 生成所有警告信息

说明-O0-O1-O2-O3 是编译器的优化选项的 4 个级别,-O0 表示没有优化,-O1 为缺省值,-O3 优化级别最高。

相关推荐
二宝哥20 分钟前
CentOS 7.9 离线安装 Nginx 并配置openssl1.1.1
linux·nginx·centos
程序员老陆32 分钟前
说一说FFmpeg6在Linux平台的编译
linux·运维·服务器·ffmpeg
IT摆渡者1 小时前
VM EXSI7.0存储硬盘故障处理
大数据·linux·github
赵民勇2 小时前
systemd-cgtop命令详解
linux·运维
hhwyqwqhhwy2 小时前
Ubuntu22.04 安装vitis
linux
刚入门的大一新生3 小时前
Linux-Linux第一个系统程序-进度条
linux·运维·服务器
wuminyu3 小时前
JDK21解决虚拟线程IO阻塞原理剖析
java·linux·c语言·jvm·c++
茫忙然3 小时前
Linux提权辅助查询工具——BinLens的安装和使用
linux·提权·binlens
FlightYe3 小时前
linux系统编程(八):阻塞与非阻塞IO对比
android·linux·运维·服务器·github·vim
雾时之林5 小时前
Linux---计算机网络常见面试题
linux·运维·计算机网络