【C语言】程序环境

文章目录

  • 一、程序的翻译环境和执行环境
  • 二、翻译环境
    • 2.1 详解编译+链接
      • 编译又分为三个阶段:
        • 1.预编译
        • 2.编译
        • 3.汇编
      • 链接
  • 三、执行环境

一、程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境:

  1. 翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  2. 执行环境,它用于实际执行代码。

二、翻译环境

翻译环境包括编译和链接两个过程,一个.c文件经过翻译环境(即编译器和链接器)后,最终变成一个.exe文件。

编译是将源代码翻译成目标代码(即机器语言)的过程。

链接是将多个目标文件和库文件链接成一个可执行文件的过程。

【C语言】程序环境_第1张图片

组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

VS中的编译器叫cl.exe,链接器叫link.exe。

2.1 详解编译+链接

编译又分为三个阶段:

  1. 预编译(预处理)指令:gcc -E test.c -o test.i
  1. 头文件的包含
  2. 注释的删除
  3. #define定义的符号的替换

及预处理指令相关(#pramga pack等)

  1. 编译 gcc -S test.c

编译即把C语言代码转换成二进制代码

  1. 语法分析
  2. 词法分析
  3. 语义分析
  4. 符号汇总(全局符号)
  1. 汇编 gcc -c test.c

生成.o文件,把汇编代码转换成二进制的指令
形成符号表

在vscode写这样一段代码:

#include //头文件
#define M 1
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for(i = 0; i < 10; i++)//打印
    {
        printf("%d ",arr[i]+M);
    }
    return 0;
}
1.预编译

用指令将预处理(-E)的结果输出(-o)到test.i文件里,可以看到,前面一大堆的内容其实是头文件的内容(#include),最后才是test.c中的代码,与test.c不同的是,注释被删除,#define定义的符号被替换。
【C语言】程序环境_第2张图片

2.编译

gcc test.i -S指令,会生成一个test.s的文件。
【C语言】程序环境_第3张图片
这其实是把C语言代码翻译成了汇编代码,在汇编过程中,进行了语法分析,词法分析,语义分析,符号汇总相关工作。
假如有这样一段代码:

#include 
extern int Mul(int x,int y);
int Add(int x,int y)
{
    return x+y;
}
int g_val = 12int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for(i = 0; i < 10; i++)
    {
        printf("%d ",arr[i]);
    }
    return 0;
}

符号汇总便是把Mul、Add、g_val、main汇总起来。

3.汇编

gcc test.i -c指令,会生成一个test.o文件(VS上是.obj),即目标文件(二进制文件)。
【C语言】程序环境_第4张图片
对每个.o文件,都会根据汇总的符号形成符号表

链接

把所有.o文件链接起来,生成.exe可执行程序

在这个过程中要进行:

  1. 合并段表:合并段,调整段偏移
  2. 符号表的合并和重定位:汇总所有符号,定位正确的虚拟地址

【C语言】程序环境_第5张图片

三、执行环境

执行环境是程序在运行时所处的环境,包括操作系统、硬件平台、运行库、系统配置等因素。程序在不同的执行环境下可能会有不同的行为、性能和可移植性,因此程序员需要考虑执行环境的影响,并编写可移植的代码。

你可能感兴趣的:(C语言,c语言,c++)