『Linux - gcc / g++』c程序翻译过程

简介: 『Linux - gcc / g++』c程序翻译过程

前言

在计算机中的每一个程序是由代码变化而来的,但是事实上来说,用 c/C++ 写出的代码是不能被计算机识别的,其中必须经过一系列的过程才能使这个代码能成功的被计算机识别;

这几个过程分别为:

预处理 编译 汇编 链接

在经历过这几个过程之后才能将代码转换为一个可执行程序;


预处理 -E

在预处理阶段时一般会进行:

  • 去注释 - 将源文件中的注释使用"空格"代替;
  • 宏替换 - 若是源文件中存在以#define定义的宏,则将其替换;
  • 头文件展开 - 将头文件进行展开;
  • 条件编译 - 根据条件编译中的条件,留下正确条件;

该些操作一般为文本操作,且该些操作结束后也仍为c/C++;

g++ -E test.cpp test.cpp文件进行预处理,并将预处理后的结果显示在显示器上;
g++ -E test.cpp -o test.i test.cpp文件进行预处理,同时指定生成一个 test.i临时文件;
-E 指令 从现在开始进行程序的翻译,如果预处理完成则停止;

从上图可以看出预处理前后的区别

可以看出两个文件大小的差距,源文件中的代码量大概只有23行,而再进行预处理过后,代码量变成接近三万行;


编译 -S

编译这个过程则是将预处理后的 .i 文件进行翻译,将c/C++代码翻译成汇编代码 .s文件;

g++ -S test.i 或是 g++ -S test.i -o test.s test.i文件编译成汇编语言 , 两种方法都可以生成test.s文件 ; 第二种方法可以指定生成文件的文件名(这里后缀一般不影响);
g++ -S test.cpp -o test.s 作用同上,唯一不同的为这里将从test.cpp文件开始进行翻译,途中将要重新进行一次预处理;;
-E 指令 从现在开始进行程序的翻译直到编译完成;


汇编 -c

在这个阶段过后,.s文件将会被转为可重定向二进制目标文件( .o 文件);

虽然这里转化为了二进制文件,但是仍然不能被计算机直接进行识别;

g++ -c test.s 或是 g++ -c test.i -o test.o 将汇编语言文件 test.s 进行汇编生成可重定向二进制目标文件 test.o
od 命令 将指定内容文件以八进制、十进制、十六进制、浮点格式或ASCII编码字符方式显示。默认使用的是八进制;
-c 指令 从现在开始进行程序翻译,直到汇编结束。

[如图所示为使用vim打开时所显示的为二进制]

这里所生成的可重定向二进制文件并不能被执行;

这里或多或少可能会存在权限问题,因为所生成的可重定向二进制文件的权限为666 & (~umask)为664;

即没有运行的权限,为了排除该情况,修改文件权限;

但即使修改了文件权限也依然不能运行;

需要打开该文件即可以使用od命令将文件打开;


链接

这也是程序翻译的最后一个步骤,即将多个.o 或者 .obj 文件合并成一个可执行程序 .exe ;

g++ test.cpp -o test 或 g++ -o testtest.cpp test.cpp源文件编译生成 test可执行程序;

然而在链接这一过程中也有分情况,分别为动态链接与静态链接;


动静态链接

在这之前首先要介绍两个命令:

ldd filename file filename
查看该文件所依赖的库文件 可以查看文件的可执行程序状态(位数、动态链接等)

一般的连接方式分为两种:

a.动态链接 b.静态链接
需要动态库 需要静态库

在调用函数中总是会包含各种头文件,但只有头文件是并不能将程序编译通过的;

头文件中只包含了各个函数的声明,而函数的定义一般以库的形式展示;

步骤一般为,在调用函数过后,从头文件中找到函数的声明,再去对应的库中找到函数的定义从而进行调用;

头文件 : 用来提供函数的声明 库文件 : 用来提供函数的定义(实现)

自己写的源文件包含头文件,链接库文件才能生成一个可执行程序;

系统\库 动态库 静态库
Linux .so .a
Windows .dll .lib

在安装vs2019或者vs2022这种编译器时,虽然叫做配置环境,但是本质上是在安装所用语言的头文件以及库文件;

C程序是脱离不开库文件的;

在Linux中,许多的命令也是利用c语言实现的,例如在Linux中使用的ls命令;

在汇编过后所生成的可重定向二进制目标文件;

#include<iostream>
int main()
{
  std::cout << "it's a test fail" << std:: endl;
  return 0;
}

从该文件中可以看到,该文件包含了一个文件 ,且调用了流插入<<流提取>>;

而这里生成的可重定向二进制文件只是将自己写的源文件中的代码生成可重定向的二进制目标文件;

至于代码中所包含的头文件以及使用流插入流提取并没有进行操作;

该操作将会在最后一步的链接过程中;

链接过程将会把该重定向二进制文件与对应的库文件进行链接最终生成一个可执行程序;(头文件在预处理阶段被展开)

静态链接 动态链接
原理 在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代码都包含到可执行文件中去。因此,链接器需要知道参与链接的目标文件需要哪些函数,同时也要知道每个目标文件都能提供什么函数,这样链接器才能知道是不是每个目标文件所需要的函数都能正确地链接。如果某个目标文件需要的函数在参与链接的目标文件中找不到的话,链接器就报错了。目标文件中有两个重要的接口来提供这些信息:一个是符号表,另外一个是重定位表。 在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。
缺点 静态库的缺点为,若是多个文件同时调用同一个函数,则可能出现在一个项目中出现大量重复代码; 动态库链接的缺点即为过于依赖动态库;
方法 g++ test.cpp -o test -static
(-static : 表明使用静态链接的方式形成可执行程序)
g++ test.cpp -o test (默认即为动态链接)

  1. 一般的机器可能会因为没有静态库而导致静态链接失败;
    在Linux中,动态链接必须使用 .so 动态库文件;
    静态链接必须使用 .a 静态库文件;
  2. 若是没有静态库文件则需要进行安装 :
c静态库安装命令 C++静态库安装命令
(sudo yum install -y glibc-static) (sudo yum install -y libstdc+±static)
相关文章
|
4月前
|
安全 Linux Shell
Linux上执行内存中的脚本和程序
【9月更文挑战第3天】在 Linux 系统中,可以通过多种方式执行内存中的脚本和程序:一是使用 `eval` 命令直接执行内存中的脚本内容;二是利用管道将脚本内容传递给 `bash` 解释器执行;三是将编译好的程序复制到 `/dev/shm` 并执行。这些方法虽便捷,但也需谨慎操作以避免安全风险。
239 6
|
5月前
|
网络协议 Linux
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
742 2
|
5月前
|
Linux Python
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
79 2
|
3月前
|
Linux 编译器 C语言
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
|
3月前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
88 1
|
4月前
|
消息中间件 分布式计算 Java
Linux环境下 java程序提交spark任务到Yarn报错
Linux环境下 java程序提交spark任务到Yarn报错
56 5
|
4月前
|
Linux 编译器 C语言
Linux内核对GCC版本的检测
Linux内核对GCC版本的检测
|
前端开发 rax Linux
Linux 程序 Linux编译 Linux编译过程的来龙去脉
Linux 程序编译过程的来龙去脉 大家肯定都知道计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python、Ruby、MATLAB 、JavaScript。
1235 0
|
2月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
141 8
|
2月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
564 6