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 优化级别最高。

相关推荐
orion578 小时前
Missing Semester Class1:course overview and introduction of shell
linux
用户1204872216115 小时前
Linux驱动编译与加载
linux·嵌入式
用户8055336980321 小时前
Input 子系统架构:Core、Handler、Driver 三层是怎么协作的
linux·嵌入式
用户8055336980321 小时前
RK-Forge外设系列开篇 - 把板子从「能启动」变成「能用」:Ethernet/SPI/MMC 三个纯接线外设
linux·github·嵌入式
七歌杜金房1 天前
我终于又有了自己的 Linux 电脑
linux·debian·mac
tntxia2 天前
linux curl命令详解_curl详解
linux
扛枪的书生2 天前
Linux 网络管理器用法速查
linux
顺风尿一寸3 天前
Java Socket 内核之旅:从 SocketChannel.read() 到 tcp_recvmsg 与 epoll 的完整调用链路
linux
XIAOHEZIcode3 天前
Ubuntu 终端美化全栈指南:Bash 到 Kitty 踩坑实录
linux·ubuntu·命令行
唐青枫3 天前
别再只会用 cron:Linux systemd Timer 定时任务实战详解
linux