C-程序执行环境

目录

一、C语言的相关文件

二、翻译环境

        1.编译

        (1)预编译阶段

       (2)编译

        (3)汇编

        2.链接

        (1)合并段表

        (2)符号表的合并与重定位


一、C语言的相关文件

        在使用VS编译并执行程序时,观察工程所处的目录,可以发现主要有以下几类文件:

        a.后缀为.c的文件                源文件

        b.后缀为.obj的文件             目标文件

        c.后缀为.exe的文件            可执行文件

        本文将对这些文件的作用以及由来做出解析。

关于环境

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

                a.翻译环境:在此环境中,源代码被转换为可执行的机器指令

                b.执行环境:用于实际执行代码

二、翻译环境

                由于VS无法直观观察到源文件编译的整个过程,使用Linux中的gcc环境做为演示。

                为了方便观察,对以下两个源文件进行操作:

// add.c
int Add(int x ,int y)
{
    return x+y;
}
// test.c
#include <stdio.h>

#define a 20
// 声明其他源文件中的函数
extern int Add(int x, int y);

int main()
{
    int b = 10;
    int c = Add(a, b);
    printf("%d\n", c);
    return 0;
}

                在翻译环境中,执行程序时源文件重要经过两个步骤:

                a.编译

                b.链接

        1.编译

                通过编译,源文件生成了目标文件。

                但编译的整个过程又可划分为三个阶段:预编译;编译;汇编。

        (1)预编译阶段

        预编译阶段也成为预处理阶段。

        在gcc命令中使用-E选项对源文件进行预处理,使用-o指令将预处理后的内容重定位到test.i中。如下:

gcc test.c -E -o test.i

       使用ls -la命令查看当前文件夹内的文件,可见新增一个名为test.i的文件。使用vim编辑器打开此文件。可见如下(包含的头文件过长,仅截取距离main函数较近片段):

         与源文件进行对比,可见包含的<stdio.h>变成了大段的代码,这一段代码就是该库函数中的内容。使用#define定义的a所在行也消失了,在main函数中的a则变成了预定义的20。对于extern所在行的注释也被删除了。

        对于预处理过程所执行的操作,可总结为三步:

        a.头文件的替换;

        b.注释的删除;

        c.#define 定义的符号的替换。

       (2)编译

        编译阶段是整个编译过程中最重要的步骤。这个阶段将预处理后的代码翻译为了汇编代码。

        在gcc命令中使用-S对预处理后的内容进行编译,同样使用-o输出到指定文件。

gcc test.i -S -o test.s

         可见新增了test.s的文件。使用vim打开如下:

         对于汇编代码,不做详解。

        但在这一步主要进行了以下操作:

        a.语法分析;

        b.词法分析;

        c.语义分析;

        d.符号汇总。

        对于符号汇总,以test.c做简要解释。

                对于test.c,可简要看作main函数+extern声明的Add函数。(以及其他全局变量)

                在内存中,对于这些内容,都会有对应的地址。

                符号汇总即将这些内容及其地址生成一个此文件对应的表格。

        (3)汇编

        汇编是编译过程的最后一步。这一步将汇编代码转换为目标文件。

        在gcc命令中使用-c选项生成目标文件,-o输出到指定文件。

        gcc test.s -c -o test.o

         可见新增了test.o的文件。使用vim打开会是如下情况:

         这是因为目标文件中存放的是二进制代码。

        在这一步的操作中,生成了符号表。

        2.链接

        链接,即将不同源文件生成的目标文件进行链接,为程序的执行做好准备。

        主要有两项内容:

        (1)合并段表

        (2)符号表的合并与重定位

        test.c在编译过程中的符号汇总上已有讲述。add.c所操作的符号汇总与之类似。

        但需要注意一点,在test.c中,指向声明的Add函数的地址并不是实际上Add函数的地址,而add.c中的Add函数的定义才是实际上的地址。这一步就是将两个源文件的符号表进行合并,并将其中名称相同的内容所指向的地址修改为实际地址。如test.c中的Add与add.c中的Add进行合并,但是保留add.c中Add的实际地址。

        使用gcc对程序执行所需的源文件进行操作,生成可执行文件:

gcc test.c add.c -o test.out

        可见生成了test.out的文件。

二、执行环境

        在linux环境中,我们使用"./+可执行文件"的格式对程序进行执行。如下:

       ./test.out

        如下:

         关于程序的执行过程,主要包含以下几个部分:

        1.程序必须载入内存中。有操作系统就由操作系统完成;独立环境必须手动安排。

        2.程序开始执行。接着就调用main函数。

        3.开始执行程序。在这个过程中,不同类型(全局和局部)会调用不同的内存区块参与执行。静态内存中的变量会在整个过程中一直保存它们的值。

        4.终止程序。包括正常的终止main函数;也可能是遇到错误或断电等意外终止。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值