11. Linux C编程

news/2025/2/6 20:33:35/文章来源:https://www.cnblogs.com/FlurryHeart/p/18701642

一、GCC、glibc和GNU C的关系

  GCC 全程 GUN Compiler Collection,是 GNU 项目的一部分,主要是一套编译器工具集,支持多种编程语言,包括 C、C++、Object-C、等。GCC 最初作为 GUN 操作系统的官方编译器,用于编译 GNU/Linux 系统和应用程序。它是自由软件,遵循 GNU General Public Licensse(GUN GPL)发布。

  GCC 的主要作用是将源代码编译成机器语言,生成可执行文件或库文件。它也提供了一些优化选项,可以在编译过程中优化代码,提供程序运行的效率。

  glibc,全程 GNU C Library,是 GNU 项目的一部分,是 C 语言标准库的一个实现版本,为 C 语言提供了标准的 API,包括输入输出处理、字符串操作、内存管理等。glibc 是 Linux 系统上最常用的 C 标准库实现之一,它实现了 C 标准规定的所有标准库函数以及 POSIX(可移植操作系统接口)的扩展。

  GCC 使用 glibc 作为其 C 语言程序的标准库。当 GCC 编译 C 语言程序时,程序中使用的标准库函数是通过 glibc 提供的。GNU C 是 GCC 中实现的 C 语言的一个版本,包含了对 C 语言标准的支持以及 GUN 特有的扩展,这些扩展可以在使用 GCC 编译程序时通过特定的编译选项启动。

  总的来说,GCC 是编译器,负责将源代码转换成可执行代码;glibc 是运行时库,提供程序运行所需的标准库函数和操作系统服务的接口;而 GNU C 则定义了 GCC 支持的 C 语言的标准和扩展。这三者共同构成了 GUN/Linux 系统下开发和运行 C 语言程序的基础。

二、什么是POSIX标准

  POSIX,全程为 “可移植操作系统接口”(Portable Operating System Interface),是一组标准,用来确保各种不同的操作系统能够提供相同的应用编程接口(API)。POSIX 标准的主要目的是促进应用软件与多种类型的操作系统之间的兼容性。通过遵循 POSIX 标准,开发人员可以编写能够在各种不同系统上运行的程序,而无需对程序进行大量修改。

  POSIX 标准的主要内容包含:

  • 系统调用和库:定义了操作系统应提供的核心服务,如文件系统操作、进程管理和线程控制。
  • Shell 和工具:规定了标准命令行接口和一系列基本工具,如 awk、echo 等。
  • 程序接口:包括语言、函数库等接口规范。是程序能够在任何遵循 POSIX 的操作系统上运行。

三、一个简易的C程序

  首先,我们需要在 Linux 系统上安装 GCC 编译器来编译 C 程序。

sudo apt install -y gcc

  安装完 GCC 后,我们可以在终端中输入命令查看 GCC 版本来确定 GCC 是否安装成功。

gcc -v

  我们新建一个 main.c 文件,用来编写 C 程序。

#include <stdio.h>int main(void)
{printf("Hello world!\n");return 0;
}

  编写完 C 程序之后,我们进入该目录,在终端中使用 GCC 编译程序。

gcc -o a.out main.c

  然后,我们运行编译生成的可执行文件。

./a.out

四、一个稍微复杂点的C程序

  我们新建一个 hello.h 头文件,它的内容如下:

#ifndef __HELLO_H__
#define __HELLO_H__#include <stdio.h>void say_hello(char *name);#endif // !__HELLO_H__

  然后,我们在新建一个 hello.c 源文件,它的内容如下:

#include "hello.h"void say_hello(char *name)
{printf("Hello %s, nice to meet you!\n", name);
}

  接着,我们在修改 main.c 源文件,它的内容如下:

#include "hello.h"int main(void)
{say_hello("Sakura");return 0;
}

  此时,我们在终端中运行 GCC 编译程序时需要将链接的源码文件都编译上。

gcc -o a.out main.c hello.c

  然后,我们运行编译生成的可执行文件。

./a.out

五、GCC的编译过程

【1】、预处理命令

  在 C 语言编译工程中,预处理是其中的第一个阶段,它的主要目的是处理源代码文件的预处理指令,将它们转换成编译器可以识别的形式。预处理主要包含 宏替换文件包含条件编译注释移除 等几种任务。预处理的输出通常是经过预处理后的源代码文件,它会被保存成一个临时文件,并作为编译器的输入。预处理器处理后的文件通常会以原始源文件大,以为它会展开宏和包含其它文件的内容。

gcc -E 源文件.c -o 预处理后的文件.i
  • -E:Expand(展开)的缩写,该选项指定 gcc 执行预处理操作。
  • -o:output(输出)的缩写,该选项用于指定输出文件名。
  • 预处理后的文件通过以 .i(intermediate,中间的缩写)作为后缀。

【2】、编译

  编译阶段,编译器会将经过预处理的源代码文件转换成汇编文件。在这个阶段,编译器会将源代码翻译成机器能够理解的中间代码,包括 词法分析语法分析语义分析优化 等过程。编译器会检查代码的语法和语义,生成对应的汇编代码。编译阶段是整个编译过程中最复杂和耗时的阶段之一,它对源代码进行了深入的分析和转换,确保了程序的正确性和性能。

gcc -S 预处理后的文件.i -o 汇编文件.s
  • -S:Source(源代码)的缩写,该参数指定 GCC 将预处理后的源码编译成汇编语言。
  • 通常编译后的汇编文件以 .s(Assembly Source,汇编源码)作为后缀。

【3】、汇编

  汇编阶段是 C 语言编译过程中的重要阶段,它将编译器生成的中间代码或汇编代码转换成目标机器的机器语言代码,也就是目标代码。这个阶段由汇编器(Assembler)完成,其主要任务是将汇编指令翻译成目标机器的二进制形式。主要包含以下几个任务:符号解析指令翻译地址关联重定向代码优化。最终,汇编器会将翻译和处理后的目标代码输出到目标文件中,用于后续的链接和生成可执行程序或共享库文件。

gcc -c 汇编文件.s -o 机器码文件.o

【4】、链接

  链接阶段,由链接器完成。链接器将各个目标文件以及可能用到的库文件进行链接,生成最终的可执行程序。在这个阶段,链接器会解析目标文件中的符号引用,将将它们与符号定义进行匹配,以解决符号的地址的关联问题。链接器还会处理全局变量的定义和声明,解决冲定位问题,最终生成可执行文件或共享库文件。

  C 语言的链接共有三种方式:静态链接动态链接混合链接。三者的区别就在于链接器在链接过程中对程序中库函数调用的解析。
静态链接 将所有目标文件和所需的库在编译时一起打包进最终的可执行文件。库的代码被复制到最终可执行文件中,使得可执行文件变得自包含,不需要在运行时查找或加载外部库。

gcc -static 机器码文件.o -o 可执行文件
  • -static:该参数指示编译器进行静态链接,而不是默认的动态链接。

  动态链接 时,库在运行时被加载,可执行文件包含了需要加载的库的路径和符号信息。动态链接的可执行文件比静态链接的小,因为它们共享系统级的库代码。与静态链接不同,库代码不会包含在可执行文件中。

gcc 机器码文件.o -o 可执行文件

  我们也可以将自己编写的部分代码处理为动态库。

gcc -fPIC -shared -o lib共享库.so 机器码文件.o
  • -fPIC:告诉编译器为 “位置无关代码”(Position Independent Code)生成输出。它允许共享库被加载到内存中的任何位置,而不影响其执行。这是因为位置无关代码使用相对地址而非绝对地址进行数据访问和函数调用,使得库在被不同程序加载时能够灵活地映射到不同的地址空间。
  • -shared:这个选项指示 GCC 生成一个共享库而不是一个可执行文件。共享库可以被多个程序同时使用,节省了内存和磁盘空间。
  • 按照惯例,Linux 下的共享库名称以 lib 开头,扩展名为 .so(表示共享对象)。

  我们要链接自己的共享库的语法格式如下:

gcc 机器码.o -L 共享库路径 -l 共享库 -o 可执行文件

  如果我们执行上述代码报错时,可能是因为没有找到动态链接库文件,导致链接失败无法执行。Linux 的默认动态链接库文件夹是 /lib/usr/lib,而我们自己的共享库不在其中,所以我们在执行过程中指明额外的动态链接库文件夹。

LD_LIBRARY_PATH=共享库路径 ./共享库

  混合链接 的某些库静态链接,而其它库动态链接。这种方式结合了静态链接和动态链接的优点。

ar crv 静态库.a 机器码文件.o
  • ar:归档命令,用于处理静态库文件。
  • crv:ar 命令的选项,由三个字符组成,每个字符代表一个选项。
    • c:创建归档文件。如果指定的归档文件不存在,ar 会创建它。
    • r:替换归档文件中现有的文件或者向归档文件中添加新文件。
    • v:详细模式(verbose mode),在处理文件时显示详情信息。使用这个选项,ar 会列出它正在执行的操作,包括哪些文件被添加或替换。
  • 按照惯例,Linux 下的静态库文件名以 lib 开头,并以 .a 作为文件扩展名。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/879800.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024.2.6鲜花

初探牛顿迭代?推歌 《以恋结缘》 诚、意地の悪い神の所业か? 奇迹?縁?袂触合う不思议 花ひとひら揺れて 不意に宿ってた うなじ解いてく春风 戯れはそこそこに 恋手ほどきしてくだしゃんせ 汤気にほんのり頬染て 夜风に愿ふ …いざ!!蝶と舞ひ花となりて 衣を乱して祓いま…

megatron 2. TP和PP实现

megatron 源码阅读第二篇, 看了TP和PP的对应实现训练并行实现 TensorParallel 张量并行代码路径, 代码路径: megatron/core/tensor_parallel 主要包含Linear / VocabEmbedding / cross_entropy 三部分. Linear 参数初始化 如果是从checkpoint热启, perform_initialization需要打…

【Azure Policy】当Azure策略组中存在多个修正任务时候时的批量处理办法

问题描述 在分配一组策略中包含了很多修正任务时候,从门户上,只能选择一个修正任务执行。 如下图:是否有好的办法,执行全部的修正任务呢?问题解答 从Azure门户的设计来看,只能选择一个修正任务是设计使然。如果想批量执行全部的修正任务,需要使用PowerShell脚本来循环执…

Kotlin空安全

前言 访问空引用的成员变量就会导致空指针异常,在Java中被称作NullPointerException,简称NPE,Kotlin中NPE产生的原因只可能是以下几种:显式调用 throw NullPointerException()使用了!!操作符数据在初始化时不一致,例如:传递一个在构造函数中出现的未初始化的 this 并用于…

Kotlin控制流程

条件与循环 if表达式 Kotlin中的if与Java中的if大致上都差不多,但是Kotlin中没有三元运算符(A ? B : C),可以用if表达式作为代替,例如: Java int a = int a = System.currentTimeMillis() % 2 == 1L ? 1 : 0; Kotlin val a = if (System.currentTimeMillis() % 2 == 1L…

第一次用Markdown

标题 标题2 标题3 标题4 字体 字体 字体姓名 性别 年龄张三 男 20![das]() baidu

【测试基础】web3.0介绍

web3.0介绍 Web3.0也被称为下一代互联网,是对当前互联网(Web2.0)的演进和升级。其目标是实现一个更加去中心化、安全、用户拥有数据主权且具有更好互操作性的互联网环境。Web3.0的核心技术包括区块链、智能合约和加密货币等。 web2.0与web3.0区别 Web2.0和Web3.0的主要区别在…

区块链原理、技术与实践

区块链介绍 区块链是一种分布式账本技术,允许多个参与者共同维护一个不断增长的数据记录列表,每个区块包含一系列交易记录,并通过密码学方法与前一个区块链接起来,形成一个不可篡改和不可逆的链条。 这种基于共识的机制使得区块链具有高度的安全性和透明性。 区块链与传统W…

《高效能人士的七个习惯》

情感账户 勇气和体谅 大石头 自传式回应、同理心倾听:用你的话反映他们的感受和意思,而不是去评论、去判断是否正确

高效能人士的七个习惯

情感账户 勇气和体谅 大石头 自传式回应、同理心倾听:用你的话反映他们的感受和意思,而不是去评论、去判断是否正确

新春“码”启 | Cocos 3D 微信小游戏(第5天):分包构建和上传发布(完美收官)

新春开发 Cocos 3D 微信小游戏计划的第 5 天,详细介绍了如何利用Cocos Creator开发并发布一款3D微信小游戏,包括游戏状态机的设计理念,和微信小游戏主包大小限制时的解决方案——分包策略。从游戏设计、开发、调试到最后成功发布的全过程,为想要进入微信小游戏开发领域的开…

爬虫随笔(一)

爬虫随笔,某牛前几天一直在看js逆向,现在分享一下本人近期学习记录首先分享一个网站,这个网站可以获得request所需要的header和cookie https://curlconverter.com/ 爬取网站就不挂了简单观察发现,该网站是滑动加载,我们可以在滑动加载时获得我们所需要的接口,发现两个链…