前言
本文先聚焦 sudo 白名单的极简配置逻辑,教你安全放开必要权限;再拆解 GCC/G++ 最核心的编译用法,让你快速掌握 Linux 下 C/C++ 程序编译的关键步骤。
📚 Linux 入门篇
🔧 Linux 工具篇
目录
一、sudo 白名单的配置详解
二、C/C++ 开发环境的核心支撑 —— 头文件与库文件
三、GCC 与 G++ 的本质区别
四、编译的四个核心阶段
4.1 预处理:宏替换与代码准备
4.2 编译:生成汇编代码
4.3 汇编:生成目标代码
4.4 链接:生成可执行文件
五、函数库:静态库与动态库
5.1 基础概念与核心特性
5.2 GCC 编译时的链接行为
【file指令】
5.3 链接的特殊情况与混合链接
5.4 优缺点对比
5.5 扩展知识:可执行文件格式与调试构建
我们在使用普通用户时,若想用 root 权限创建文件等操作,又不想切换账号,就可以借助 sudo 临时获取 root 权限。但一般情况下,普通用户直接用 sudo 提权会失败,这是因为 sudo 的权限控制由 /etc/sudoers 文件(及相关配置)管理,普通用户尚未被拥有权限的用户(如 root)在该文件中配置进 “白名单”(即设置好对应的权限规则),所以操作会被拒绝。
【就像这样的场景】:

【如何将普通用户加入白名单】:

由于sudoers文件的拥有者是root所以得使用root用户添加,切换root账号,打开ect目录下的sudoers文件,在图片黄色格子圈的地方,按上述示例添加你的用户


保存并退出文件后,再次尝试:

上述图片可以看到,用root身份创建file文件创建成功
我们能在 Windows 或 Linux 上开展 C/C++ 开发,核心原因在于系统中提前或后续安装了 C/C++ 开发相关的头文件和库文件。
C/C++ 开发环境不只是 Visual Studio(VS)、GCC、G++ 这些编译工具,语言本身的头文件和库文件才是更关键的支撑。像安装 VS2019、VS2022 时,选择对应的开发包,其实就是在同步下载 C 语言的头文件和库文件。对于编译型语言而言,安装开发包必然要下载并安装对应的头文件与库文件,而且 C 的头文件和库文件在 Windows 系统上也是存在的。
【软件版本的裁剪:条件编译的应用】:
以软件的社区版(免费)和专业版(付费,功能更丰富)为例,提供这些软件的公司并不需要维护两份完全独立的代码。
借助 条件编译 技术,公司可以根据不同的编译条件,对社区版不需要的功能进行裁剪。比如在代码中通过 #ifdef #ifndef 等条件编译指令,判断当前编译的是社区版还是专业版,从而决定是否包含某些专业功能的代码段,这样大大减少了代码维护的成本。
libstdc++)。核心差异:编译 .c 文件时,GCC 会默认按 C 语言语法处理,而 G++ 会默认按 C++ 语法处理;编译 .cpp 文件时,两者都会按 C++ 语法处理,但 G++ 会自动链接 C++ 库,GCC 则需要手动指定 -lstdc++ 选项才能链接 C++ 库。

第一次编译失败是因为没有链接到C++的库,第二次加入-lstdc++选项才链接成功
要深入理解 GCC/G++ 的工作,首先得知晓代码从源码到可执行文件的四个关键阶段,每一步都在为最终生成可运行程序铺路。
预处理阶段主要负责对源码进行 “初步加工”,包括宏替换、头文件展开、条件编译执行以及注释删除等操作。
gcc -E test.c -o test.i -E 选项的作用是让 GCC 在完成预处理后就停止后续的编译流程。-o 用于指定输出文件,这里生成的 test.i 文件就是经过预处理后的 C 原始程序,里面已经完成了宏替换、头文件包含等操作。这一阶段,GCC 会先严格检查代码的规范性,排查语法错误。若代码无误,就会将其翻译成汇编语言。
gcc -S test.i -o test.s -S 选项能让 GCC 只进行编译,不执行后续的汇编步骤,最终生成汇编代码文件 test.s,我们可以通过查看这个文件来了解代码对应的汇编指令。汇编阶段是把编译阶段生成的 .s 汇编文件转换成机器可识别的目标文件(.o 文件)。
gcc -c test.s -o test.o -c 选项会让 GCC 完成汇编操作,生成二进制格式的目标文件 test.o,不过这个目标文件还不能直接执行,需要后续的链接步骤。成功编译后,就进入链接阶段。链接的作用是将目标文件与所需的函数库(如 C 标准库)进行关联,最终生成可执行文件。
gcc test.o -o test .o 与系统库等资源链接起来,生成可执行文件 test,此时就可以直接运行这个程序了。【静态库】:
.a,windows下为.lib。【动态库】:
.so**(如** libc.so.6**),Windows 下为 .dll**。【默认动态链接】:
GCC 编译生成可执行程序时,默认采用动态链接方式。例如:
gcc test.c -o test生成的 test 是动态链接程序,可通过 file test 验证(输出含 “dynamic executable” 字样),再用 ldd test 可查看其依赖的动态库列表。
【file指令】
file [选项] 文件或目录...-c:详细显示指令执行过程,便于排错或分析程序执行的情形。-z:尝试去解读压缩文件的内容。【静态链接的实现】:
若要强制静态链接,需添加 -static 选项:
gcc -static test.c -o test_static此时程序会链接静态库(需系统安装对应静态库包,如 CentOS 下可通过 a 安装静态 C 标准库和 C++ 标准库)。用 ldd hello_static 验证,会显示 “not a dynamic executable”,说明无动态库依赖。
【无静态库时强制静态链接】
若系统没有所需静态库,却使用 -static 选项,编译会失败。因为静态链接必须找到对应的静态库文件才能完成 “代码嵌入” 操作。
【动态库与静态库共存时的链接优先级】
当系统同时存在动态库和静态库,且 GCC 都能找到时,默认优先动态链接。-static 的本质是改变链接优先级,强制优先选择静态库,但这种 “优先级改变” 是 “只适配一次” 的逻辑,并非所有依赖都强制静态链接。
【混合链接】
实际开发中,程序可采用混合链接(部分模块动态链接,部分静态链接)。比如,对核心功能模块链接静态库以保证独立性,对通用功能链接动态库以节省资源,但需通过复杂的编译选项或链接脚本精细控制,一般在对程序性能、体积和依赖有特殊要求的场景使用。
【动态库】
【静态库】
【补充】:

【可执行文件格式】
Linux 下可执行程序采用 ELF(Executable and Linkable Format) 格式,并非简单的二进制流,而是包含段表、符号表等结构,用于程序加载和链接。
【debug 与 release 构建】
-g 选项(如 gcc -g hello.c -o hello_debug),生成的程序包含调试信息,可通过 GDB(gdb hello_debug)进行单步调试、变量查看等操作。-O2)提升性能(gcc -O2 hello.c -o hello_release),生成的程序体积小、运行快,适合发布。