【Linux】Linux:sudo 白名单配置与 GCC/G++ 编译器使用指南

🔥 脏脏a的技术站 🔥

「在代码的世界里,脏脏的技术探索从不设限~」

🚀 个人主页:脏脏a-CSDN博客

📌 技术聚焦:Linux 环境下 GCC/G++工具的实用技巧与深度解析

📊 文章专栏:Linux

🔗 上篇回顾:Linux工具:yum和vim
本文先聚焦 sudo 白名单的极简配置逻辑 ,教你安全放开必要权限;再拆解 GCC/G++ 最核心的编译用法,让你快速掌握 Linux 下 C/C++ 程序编译的关键步骤。

目录

[🔍一、sudo 白名单的配置详解](#🔍一、sudo 白名单的配置详解)

[🎨二、C/C++ 开发环境的核心支撑 ------ 头文件与库文件](#🎨二、C/C++ 开发环境的核心支撑 —— 头文件与库文件)

[🧪三、GCC 与 G++ 的本质区别](#🧪三、GCC 与 G++ 的本质区别)

📋四、编译的四个核心阶段

[4.1 预处理:宏替换与代码准备](#4.1 预处理:宏替换与代码准备)

[4.2 编译:生成汇编代码](#4.2 编译:生成汇编代码)

[4.3 汇编:生成目标代码](#4.3 汇编:生成目标代码)

[4.4 链接:生成可执行文件](#4.4 链接:生成可执行文件)

🚧五、函数库:静态库与动态库

[5.1 基础概念与核心特性](#5.1 基础概念与核心特性)

[5.2 GCC 编译时的链接行为](#5.2 GCC 编译时的链接行为)

file指令

[5.3 链接的特殊情况与混合链接](#5.3 链接的特殊情况与混合链接)

[5.4 优缺点对比](#5.4 优缺点对比)

[5.5 扩展知识:可执行文件格式与调试构建](#5.5 扩展知识:可执行文件格式与调试构建)


🔍一、sudo 白名单的配置详解

我们在使用普通用户时,若想用 root 权限创建文件等操作,又不想切换账号,就可以借助 sudo 临时获取 root 权限。但一般情况下,普通用户直接用 sudo 提权会失败,这是因为 sudo 的权限控制由 **/etc/sudoers**文件(及相关配置)管理,普通用户尚未被拥有权限的用户(如 root)在该文件中配置进 "白名单"(即设置好对应的权限规则),所以操作会被拒绝。

【就像这样的场景】:

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

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

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

上述图片可以看到,用root身份创建file文件创建成功

🎨二、C/C++ 开发环境的核心支撑 ------ 头文件与库文件

我们能在 Windows 或 Linux 上开展 C/C++ 开发,核心原因在于系统中提前或后续安装了 C/C++ 开发相关的头文件和库文件

C/C++ 开发环境不只是 Visual Studio(VS)、GCC、G++ 这些编译工具,语言本身的头文件和库文件才是更关键的支撑。像安装 VS2019、VS2022 时,选择对应的开发包,其实就是在同步下载 C 语言的头文件和库文件。对于编译型语言而言,安装开发包必然要下载并安装对应的头文件与库文件,而且 C 的头文件和库文件在 Windows 系统上也是存在的。

【软件版本的裁剪:条件编译的应用】:

以软件的社区版(免费)和专业版(付费,功能更丰富)为例,提供这些软件的公司并不需要维护两份完全独立的代码。

借助 条件编译 技术,公司可以根据不同的编译条件,对社区版不需要的功能进行裁剪。比如在代码中通过 #ifdef #ifndef 等条件编译指令,判断当前编译的是社区版还是专业版,从而决定是否包含某些专业功能的代码段,这样大大减少了代码维护的成本。

🧪三、GCC 与 G++ 的本质区别

  • GCC:是 GNU 编译器集合的总称,支持 C、C++、Java、Fortran 等多种语言,当编译 C 代码时,它会自动调用 C 编译器。
  • G++ :是 GCC 下专门用于编译 C++ 代码的工具,本质上是 GCC 的一个前端,会自动链接 C++ 标准库(如 libstdc++)。

核心差异编译 .c 文件时 ,GCC 会默认按 C 语言语法处理,而 G++ 会默认按 C++ 语法处理;编译 .cpp 文件时 ,两者都会按 C++ 语法处理,但 G++ 会自动链接 C++ 库,GCC 则需要手动指定 -lstdc++ 选项才能链接 C++ 库。

第一次编译失败是因为没有链接到C++的库,第二次加入-lstdc++选项才链接成功

📋四、编译的四个核心阶段

要深入理解 GCC/G++ 的工作,首先得知晓代码从源码到可执行文件的四个关键阶段,每一步都在为最终生成可运行程序铺路。

4.1 预处理:宏替换与代码准备

预处理阶段主要负责对源码进行 "初步加工",包括宏替换、头文件展开、条件编译执行以及注释删除等操作。

  • 指令示例: gcc -E test.c -o test.i
    • -E 选项的作用是让 GCC 在完成预处理后就停止后续的编译流程。
    • -o 用于指定输出文件,这里生成的 test.i 文件就是经过预处理后的 C 原始程序,里面已经完成了宏替换、头文件包含等操作。

4.2 编译:生成汇编代码

这一阶段,GCC 会先严格检查代码的规范性,排查语法错误。若代码无误,就会将其翻译成汇编语言。

  • 指令示例: gcc -S test.i -o test.s
    • -S 选项能让 GCC 只进行编译,不执行后续的汇编步骤,最终生成汇编代码文件 test.s,我们可以通过查看这个文件来了解代码对应的汇编指令。

4.3 汇编:生成目标代码

汇编阶段是把编译阶段生成的 .s 汇编文件转换成机器可识别的目标文件(.o 文件)。

  • 指令示例: gcc -c test.s -o test.o
    • -c 选项会让 GCC 完成汇编操作,生成二进制格式的目标文件 test.o不过这个目标文件还不能直接执行,需要后续的链接步骤。

4.4 链接:生成可执行文件

成功编译后,就进入链接阶段。链接的作用是将目标文件与所需的函数库(如 C 标准库)进行关联,最终生成可执行文件。

  • 指令示例: gcc test.o -o test
    • 执行这条命令后,GCC 会把目标文件 test.o 与系统库等资源链接起来,生成可执行文件 test,此时就可以直接运行这个程序了。

🚧五、函数库:静态库与动态库

5.1 基础概念与核心特性

【静态库】:

  • 定义:编译链接时,会将库文件的全部代码嵌入可执行文件。
  • 后缀 :Linux 下通常为 .a
  • 特点:生成的可执行文件体积大,但运行时不依赖外部库,可独立运行。例如,若程序链接了静态数学库,编译后库代码直接 "打包" 进程序,在无对应库的环境中也能运行。

【动态库】:

  • 定义:编译链接时仅记录库引用,程序运行时由运行时链接器加载库。
  • 后缀 :Linux 下通常为**.so(如 libc.so.6)** ,Windows 下为**.dll**。
  • 特点:可执行文件体积小,多个程序能共享同一份库代码,但运行时依赖库存在。若动态库缺失,依赖它的所有程序可能都无法正常运行。

5.2 GCC 编译时的链接行为

【默认动态链接】:

GCC 编译生成可执行程序时,默认采用动态链接方式。例如:

bash 复制代码
gcc test.c -o test

生成的 test 是动态链接程序,可通过 file test 验证(输出含 "dynamic executable" 字样),再用 ldd test 可查看其依赖的动态库列表。

【file指令】
  • 功能说明:用于辨识文件类型,可判断文件是普通文本、可执行程序、压缩包、符号链接等,并能分析文件编码、架构等信息。
  • 语法file [选项] 文件或目录...
  • 常用选项
    • -c:详细显示指令执行过程,便于排错或分析程序执行的情形。
    • -z:尝试去解读压缩文件的内容。

【静态链接的实现】:

若要强制静态链接,需添加**-static** 选项:

bash 复制代码
gcc -static test.c -o test_static

此时程序会链接静态库(需系统安装对应静态库包,如 CentOS 下可通过 a 安装静态 C 标准库和 C++ 标准库)。用 ldd hello_static 验证,会显示 "not a dynamic executable",说明无动态库依赖。

5.3 链接的特殊情况与混合链接

【无静态库时强制静态链接】

若系统没有所需静态库,却使用 -static 选项,编译会失败。因为静态链接必须找到对应的静态库文件才能完成 "代码嵌入" 操作。

【动态库与静态库共存时的链接优先级】

当系统同时存在动态库和静态库,且 GCC 都能找到时,默认优先动态链接-static的本质是改变链接优先级,强制优先选择静态库,但这种 "优先级改变" 是 "只适配一次" 的逻辑,并非所有依赖都强制静态链接。

【混合链接】

实际开发中,程序可采用混合链接(部分模块动态链接,部分静态链接)。比如,对核心功能模块链接静态库以保证独立性,对通用功能链接动态库以节省资源,但需通过复杂的编译选项或链接脚本精细控制,一般在对程序性能、体积和依赖有特殊要求的场景使用。

5.4 优缺点对比

【动态库】

  • 优点
    • 资源共享:多个程序共享同一份库代码,节省磁盘空间、网络空间、和内存空间(运行时库只加载一次)。
    • 更新便捷:库更新后,只需替换动态库文件,无需重新编译所有依赖程序。
  • 缺点
    • 运行依赖:依赖的动态库缺失或版本不兼容时,程序无法运行。
    • 加载开销:运行时加载库会带来一定性能开销(虽通常可忽略,但对极致性能场景有影响)。

【静态库】

  • 优点
    • 独立性强:程序不依赖外部库,在纯净环境(无对应动态库)也能运行,适合嵌入式设备、严苛运行环境的程序。
    • 运行稳定:无动态库加载的不确定性,运行行为更稳定。
  • 缺点
    • 体积庞大:可执行文件包含库全部代码,占用更多磁盘和内存。
    • 更新繁琐:库更新后,所有依赖程序都需重新编译链接。

【补充】:

5.5 扩展知识:可执行文件格式与调试构建

【可执行文件格式】

Linux 下可执行程序采用 ELF(Executable and Linkable Format) 格式,并非简单的二进制流,而是包含段表、符号表等结构,用于程序加载和链接。

【debug 与 release 构建】

  • debug 构建 :编译时添加 -g 选项(如 gcc -g hello.c -o hello_debug),生成的程序包含调试信息,可通过 GDB(gdb hello_debug)进行单步调试、变量查看等操作。
  • release 构建 :默认不包含调试信息,且可添加优化选项(如 -O2)提升性能(gcc -O2 hello.c -o hello_release),生成的程序体积小、运行快,适合发布。
相关推荐
秉承初心3 小时前
Linux中Expect脚本和Shell的脚本核心特点解析、以及比对分析和应用场景
linux·运维·服务器·sh·exp
---学无止境---3 小时前
Linux中初始化字符设备子系统chrdev_init的实现
linux
十铭忘3 小时前
基于SAM2的眼动数据跟踪2
java·服务器·前端
Ahern_4 小时前
崖山数据库安装部署
linux·数据库
BS_Li4 小时前
【Linux系统编程】权限的概念
linux·权限
码农阿豪4 小时前
一个浏览器多人用?Docker+Neko+cpolar实现跨网共享
运维·docker·容器
cellurw4 小时前
Day67 Linux I²C 总线与设备驱动架构、开发流程与调试
linux·c语言·架构
天朝八阿哥4 小时前
Bye~~ win10!
linux·windows
孙同学_4 小时前
【Linux篇】软链接vs硬链接:Linux文件系统中的两种引用机制
linux·运维·服务器