news 2026/5/15 15:53:06

第8课:Linux开发工具(三):gcc

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第8课:Linux开发工具(三):gcc

第8课:Linux开发工具(三):gcc

一、GCC与g++的区别与使用建议

  1. 基本定位

    • GCC:纯C语言编译器,只能编译C语言代码
    • g++:C++编译器,既能编译C++代码,也能编译C语言代码,但编译C语言时会按照C++的语法规则进行编译
  2. 推荐使用方式

    • 编译C语言代码:优先使用gcc
    • 编译C++代码:优先使用g++

【核心结论】虽然g++可以编译C语言,但本质是将C语言当作C++来处理,可能存在语法兼容性问题。使用对应编译器编译对应语言是最佳实践。

  1. 历史与环境兼容性说明
    • 部分老旧Linux环境可能默认只安装了GCC,未安装g++
    • C语言编写内核、操作系统等底层代码时,使用GCC编译的代码质量更高、更贴近硬件

二、程序翻译的四个阶段(核心重点)

C/C++代码从源文件到可执行程序,必须经过预处理、编译、汇编、链接四个阶段。GCC默认会一步完成所有阶段,但我们可以通过选项让它在每个阶段结束后停下来,方便观察和调试。

1. 预处理(Preprocessing)
  • 核心工作

    1. 头文件展开:将#include包含的头文件内容完整拷贝到源文件中
    2. 宏替换:将代码中所有的宏定义(#define)替换为实际的值
    3. 去除注释:删除代码中所有的单行注释(//)和多行注释(/* */
    4. 条件编译:根据宏定义条件,保留或裁剪对应的代码段
  • 对应GCC选项与文件后缀

    • 选项:-E(大写E)
    • 作用:从当前开始进行程序翻译,完成预处理后立即停止
    • 输出文件后缀:.i(约定俗成,非强制)
    • 命令格式:gcc -E 源文件.c -o 预处理文件.i
  • 代码演示与验证
    我们使用以下测试代码code.c

    #include<stdio.h>#defineM100#defineVERSION11intmain(){#ifdefVERSION1printf("我是version1版本的功能\n");#elseprintf("我是version2版本的功能\n");#endif//printf("hello world 1, %d\n", M);//printf("hello world 2, %d\n", M);return0;}

    执行预处理命令:

    gcc-Ecode.c-ocode.i

    观察code.i文件可以发现:

    • MVERSION1已经被完全替换
    • 所有注释已经被删除
    • 代码从原来的20多行变成了800多行,这是因为stdio.h头文件被完整展开了
  • 头文件展开的本质与意义

    • 本质:将头文件的内容原封不动地拷贝到源文件的对应位置

    • 为什么要把头文件和源文件分开?

      【补充说明】主要是为了支持库的开发。当我们制作库时,只需要将头文件(包含函数声明)交给用户,而将源文件编译成二进制库文件隐藏起来,这样既可以让用户知道如何使用库,又能保护源代码不被泄露。

  • 条件编译的本质与应用场景

    • 本质:对代码进行裁剪
    • 核心应用场景:
      1. 软件版本管理:同一套代码维护免费版、社区版、企业版等不同版本
      2. 跨平台开发:根据不同操作系统编译不同的代码段
      3. 调试与发布:在调试版本中保留调试代码,发布版本中裁剪掉

    【核心结论】公司内部通常只维护一套完整的代码,通过条件编译选项生成不同功能的版本,大大降低了维护成本。

  • 防止头文件重复包含的原理
    我们经常在头文件中看到这样的写法:

    #ifndefCODE_H#defineCODE_H// 头文件内容#endif

    或者:

    #pragmaonce

    这两种写法的本质都是条件编译。当第一次包含头文件时,宏未定义,会保留头文件内容并定义该宏;当第二次及以后包含时,宏已经定义,会直接裁剪掉头文件内容,从而避免重复包含导致的重定义错误。

2. 编译(Compilation)
  • 核心工作:将预处理后的干净C语言代码,翻译成汇编语言代码

  • 对应GCC选项与文件后缀

    • 选项:-S(大写S)
    • 作用:从当前开始进行程序翻译,完成编译后立即停止
    • 输出文件后缀:.s(汇编语言源文件的标准后缀)
    • 命令格式:gcc -S 预处理文件.i -o 汇编文件.s
  • 为什么要翻译成汇编语言,而不是直接翻译成二进制?
    这是由计算机语言的发展历史决定的:

    1. 最早的编程方式是二进制编程(打孔纸带),不需要编译器
    2. 为了提高效率,人们发明了汇编语言,用助记符代替二进制指令,同时诞生了汇编器
    3. 后来为了进一步提高效率,发明了C语言。C语言的设计者没有从零开始写一个直接生成二进制的编译器,而是站在巨人的肩膀上,先将C语言翻译成汇编语言,再利用已有的汇编器生成二进制。
  • 编译器与语言的关系

    【核心结论】编程语言的语法本质上是编译器的翻译规则。我们学习C语言语法,其实就是在学习GCC等编译器如何理解和翻译我们写的代码。

  • 编译器自举原理
    这是一个非常经典的"鸡生蛋,蛋生鸡"问题:

    1. 第一代汇编编译器:用二进制直接编写
    2. 有了汇编编译器后,就可以用汇编语言编写更强大的汇编编译器
    3. 第一代C语言编译器:用汇编语言编写
    4. 有了C语言编译器后,就可以用C语言编写更高级的C语言编译器
    5. 现代的GCC、Clang等编译器,都是用C/C++编写的,自己编译自己

    这个过程就叫做编译器自举,是编程语言发展的核心动力。

3. 汇编(Assembly)
  • 核心工作:将汇编语言代码,翻译成可重定位目标二进制文件

  • 对应GCC选项与文件后缀

    • 选项:-c(小写c)
    • 作用:从当前开始进行程序翻译,完成汇编后立即停止
    • 输出文件后缀:.o(可重定位目标文件的标准后缀)
    • 命令格式:gcc -c 汇编文件.s -o 目标文件.o
  • 可重定位目标文件(.o)的特点

    • 它已经是二进制文件,用文本编辑器打开会显示乱码
    • 它不能直接运行!即使给它加上可执行权限也不行

【易错警告】很多初学者会误以为二进制文件就能运行,实际上.o文件只是半成品,它里面只包含了我们自己写的代码的二进制实现,但没有和系统库关联起来。

4. 链接(Linking)
  • 核心工作:将我们生成的目标文件(.o)与系统库文件进行关联,生成最终的可执行程序

  • 头文件与库的关系

    • 头文件(.h):只包含函数的声明,告诉编译器函数的名称、参数和返回值类型
    • 库文件:包含函数的具体实现,已经被编译成二进制

    【补充说明】开发C语言程序必须具备三个要素:

    1. 编译器(GCC/g++)
    2. 头文件(提供函数声明)
    3. 库文件(提供函数实现)

    我们安装VS时下载的"C++开发工具包",本质上就是下载了Windows平台下的C/C++头文件和库文件。

  • 查看库依赖的命令ldd
    格式:ldd 可执行文件
    示例:

    ldd code

    输出中会显示该可执行文件依赖的所有动态库,其中最重要的是libc.so.6,这就是C语言标准库,它包含了printfscanf等所有标准函数的实现。

  • 为什么.o文件不能直接运行?
    因为.o文件中只有我们自己写的代码的二进制,但我们调用的printf等标准函数的实现并不在.o文件中。链接阶段的核心任务就是找到这些函数在库中的实现,并将它们与我们的代码关联起来。

三、动静态库详解(感性认识)

库是预编译好的二进制代码集合,分为静态库动态库两种。

1. 库的分类与命名规则
系统静态库后缀动态库后缀命名格式库的真名
Linux.a.solibxxx.a/libxxx.so去掉前缀lib和后缀后的部分(如libc.so的真名是c
Windows.lib.dllxxx.lib/xxx.dll去掉后缀后的部分

【补充说明】Linux系统本身不关心文件后缀,但编译器和链接器会根据后缀来识别文件类型。

2. 动态库(共享库)
  • 形象比喻:网吧。所有学生(程序)都去同一个网吧(动态库)上网(调用函数)。

  • 工作原理

    1. 链接阶段:链接器不会将库函数的代码拷贝到可执行文件中,只会在可执行文件中记录库的路径和函数的地址
    2. 运行阶段:当程序执行到库函数时,操作系统会根据记录的地址,将动态库加载到内存中,然后跳转到库函数中执行
    3. 多个程序可以共享内存中的同一份动态库
  • 优缺点

    • ✅ 优点:节省内存(所有程序共享一份库);可执行文件体积小;库更新后不需要重新编译程序
    • ❌ 缺点:运行时需要跳转,速度稍慢;强依赖库,库缺失或版本不兼容会导致程序无法运行
3. 静态库
  • 形象比喻:买电脑回家。每个学生(程序)都把自己需要的电脑(库函数)买回家(拷贝到自己的可执行文件中)。

  • 工作原理
    链接阶段:链接器会将程序中用到的所有库函数的代码,完整地拷贝到可执行文件中

  • 优缺点

    • ✅ 优点:不依赖库,编译成功后可以独立运行;运行时不需要跳转,速度稍快
    • ❌ 缺点:可执行文件体积大;多个程序运行时,内存中会存在多份相同的库代码,浪费内存;库更新后需要重新编译程序
4. GCC链接方式控制
  • 默认方式动态链接。GCC默认会优先使用动态库进行链接,这也是工业界的最佳实践。

  • 强制静态链接:使用-static选项
    命令格式:gcc 源文件.c -o 可执行文件 -static

  • 静态链接常见报错与解决
    如果你执行静态链接命令时出现以下错误:

    /usr/bin/ld: cannot find -lc collect2: error: ld returned 1 exit status

    这表示系统中没有安装C语言静态库

    【易错警告】Linux系统默认只安装动态库,不安装静态库。

    解决方法(以CentOS/RHEL为例):

    sudoyuminstall-yglibc-static
  • 动静态链接生成文件的体积对比
    老师课堂演示结果:

    • 动态链接生成的可执行文件:约8KB
    • 静态链接生成的可执行文件:约860KB
      体积相差了100多倍,这直观地体现了静态链接的缺点。

四、GCC常用选项总结

选项作用对应阶段输出文件后缀
-E完成预处理后停止预处理.i
-S完成编译后停止编译.s
-c完成汇编后停止汇编.o
-o指定输出文件的名称所有阶段-
-Wall显示所有编译警告编译阶段-
-static强制使用静态链接链接阶段-

【记忆技巧】

  • 程序翻译的三个阶段选项:ESC(键盘左上角的三个键,注意S是大写)
  • 对应生成的文件后缀:ISO.i.s.o

五、核心命令演示

  1. 一步生成可执行文件(默认动态链接):

    gcc code.c-ocode
  2. 分步编译:

    # 1. 预处理gcc-Ecode.c-ocode.i# 2. 编译gcc-Scode.i-ocode.s# 3. 汇编gcc-ccode.s-ocode.o# 4. 链接gcc code.o-ocode
  3. 强制静态链接:

    gcc code.c-ocode-static-static
  4. 查看可执行文件依赖的库:

    ldd code
  5. 查看文件类型:

    filecodefilecode-static
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/15 15:51:03

终极跨平台视频下载解决方案:Parabolic高效下载工具深度解析

终极跨平台视频下载解决方案&#xff1a;Parabolic高效下载工具深度解析 【免费下载链接】Parabolic Download web video and audio 项目地址: https://gitcode.com/GitHub_Trending/pa/Parabolic 在当今数字媒体时代&#xff0c;您是否经常遇到无法保存在线视频的困扰&…

作者头像 李华
网站建设 2026/5/15 15:48:16

终极免费B站视频下载工具:3分钟学会如何轻松下载Bilibili视频

终极免费B站视频下载工具&#xff1a;3分钟学会如何轻松下载Bilibili视频 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mi…

作者头像 李华
网站建设 2026/5/15 15:47:14

WordPress主题Puock深度解析:轻量设计、性能优化与实战配置指南

1. 项目概述&#xff1a;一个为创作者而生的WordPress主题如果你是一个独立博主、内容创作者&#xff0c;或者正在运营一个小型媒体站点&#xff0c;大概率对WordPress又爱又恨。爱它的自由度和海量生态&#xff0c;恨它默认主题的平庸和那些“重量级”商业主题的臃肿。你需要的…

作者头像 李华
网站建设 2026/5/15 15:44:53

生成式AI零基础入门:从环境搭建到首个AI应用实践

1. 项目概述&#xff1a;从零开始的生成式AI实践指南最近几年&#xff0c;生成式AI&#xff08;Generative AI&#xff09;的热度可以说是席卷了全球。从能写代码、写文章的ChatGPT&#xff0c;到能“无中生有”生成逼真图像的Stable Diffusion&#xff0c;再到能创作音乐的Sun…

作者头像 李华