C语言从编译到运行过程详解

 更新时间:2021年09月07日 15:36:07   作者:Steven_cs  
这篇文章主要介绍了C语言从编译到运行的一个过程的相关资料,需要的朋友可以参考下面文章具体的内容

C语言从编译到运行

一、前言

最近在看CSAPP(深入理解计算机系统)然后以前也学过C语言,但是从来没有深究写好的C代码是怎么编译再到执行的。

所以现在自己学习,然后记录下来。

以最常用的hello world!程序为例 程序名: main.c

#include <stdio.h>

int main()
{
    printf("Hello world!\n");
    return 0;
}

二、C程序编译过程

hello程序的生命周期是从一个高级C语言程序开始的,为了能够运行hello.c程序,每一条C语句都被其他程序转化为一系列的低级机器语言指令。然后这些指令按照一种称为可执行目标程序的格式打包,以二进制磁盘文件的形式存放起来。目标程序也称为可执行目标文件。

编译一个 C程序可以分为四阶段:预处理阶段--->生成汇编代码阶段--->汇编阶段--->链接阶段

各个阶段的代码可以通过gcc指令来生成

如果没有gcc可以用下面指令安装

sudo apt-get build-dep gcc

安装完之后可以根据以下指令查看是否安装成功

gcc --version

安装好后用下面指令生成中间文件

gcc main.c 直接生成可执行文件 a.out
gcc -E main.c -o hello.i 生成预处理后的代码
gcc –S main.c -o hello.s 生成汇编代码
gcc –c main.c -o hello.o 生成目标代码

三、阶段过程

1、预处理阶段

gcc -E main.c -o hello.i 生成预处理后的代码

  预处理器(cpp)根据以字符 # 开头的命令,修改原始的C程序。比如mian.c中第一行的 #include<stdio.h> 命令就告诉预处理器读取系统头文件stdio.h的内容,并且把它直接插入程序文本中。同时删除注释行,添加行号和文件名标识。这样就得到了另一个C程序,通常是以 .i 作为文件扩展名。 所以经过预编译的 .i 文件是不包含宏定义的。

  处理完后我们来看看 hello.i 文件。发现原来的7行代码变成了700多行,我们的代码在最后面。而前面多出来的代码就是 .c 中#include<stdio.h>展开的代码。

2、编译阶段

gcc –S main.c -o hello.s     生成汇编代码

  编译是将源文件(hello.i)翻译成汇编文件(hello.s)的过程。中间包含词法、语法分析等步骤,具体过程可以参考《编译原理》。

  打开汇编代码我们会发现里面有很多以 . 开头的行,所有这些以 . 开头的行都是指导汇编器和链接器工作的伪指令。 我们通常可以忽略这些行。

去掉这些行后剩下的部分。

3、汇编阶段

gcc –c main.c -o hello.o 生成目标代码

汇编阶段是把编译阶段生成的 .s 文件转成 .o 的二进制目标代码。汇编器(as)将 hello.s 翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。hello.o文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。如果我们在文本编译器中打开 hello.o 文件,看到的将是一堆乱码。

你非要看就是这样

4、链接阶段

  这个阶段就是把汇编后的机器指令集变成可以直接运行的文件,而对目标文件进行链接主要是因为在目标文件中可能用到了在其他文件当中定义的字段(或者函数),通过链接来把多个不同目标文件关联到一起。

  hello 程序调用了printf 函数,它是每个 C 编译器都会提供的标准C库中的一个函数,printf 函数存在于一个名为 printf.o 的单独预编译好了的标准文件中,而这个文件必须以某种方式合并到我们的 hello.o 程序中,链接器(ld)就负责处理这种合并,结果就得到 hello 文件,它是一个可执行目标文件(简称:可执行文件),可以被加载到内存中,有系统执行。

以上就是C语言从编译到运行过程详解的详细内容,更多关于C语言从编译到运行的资料请关注脚本之家其它相关文章!

相关文章

  • VSstudio中scanf返回值被忽略的原因及解决方法(推荐)

    VSstudio中scanf返回值被忽略的原因及解决方法(推荐)

    这篇文章主要介绍了VSstudio中scanf返回值被忽略的原因及其解决方法,scanf返回值被忽略,接下来我就告诉大家该如何解决这个问题,需要的朋友可以参考下
    2022-09-09
  • C++开发之CRC校验实例详解

    C++开发之CRC校验实例详解

    这篇文章主要介绍了C++开发之CRC校验实例详解的相关资料,需要的朋友可以参考下
    2017-07-07
  • C++中四种强制转换方式的区别

    C++中四种强制转换方式的区别

    在C++中,有四种不同的强制转换方式,它们分别是静态转换、动态转换、常量转换和重新解释转换,下面通过示例代码讲解每种转换的区别,感兴趣的朋友跟随小编一起看看吧
    2023-08-08
  • 堆排序算法(选择排序改进)

    堆排序算法(选择排序改进)

    这篇文章主要介绍了堆排序算法(选择排序改进),有需要的朋友可以参考一下
    2014-01-01
  • C++实现特殊矩阵的压缩存储算法

    C++实现特殊矩阵的压缩存储算法

    在实际存储时,会发现矩阵中有许多值相同的数据或有许多零数据,且分布呈现出一定的规律,称这类型的矩阵为特殊矩阵。本文将利用C++实现特殊矩阵的压缩存储,感兴趣的可以了解一下
    2022-08-08
  • C语言深入探究栈的原理

    C语言深入探究栈的原理

    一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则
    2021-11-11
  • C语言中的rand()和rand_r()详解

    C语言中的rand()和rand_r()详解

    这篇文章主要为大家介绍了C语言中的rand()和rand_r(),具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • C++实现旋转扫描仪的示例代码

    C++实现旋转扫描仪的示例代码

    旋转扫描仪(Rotating Scanner),也称为旋转扫描仪或圆形扫描仪,是一种用于获取图像和文档的设备,下面就跟随小编一起来学习一下如何使用C++实现旋转扫描仪功能吧
    2024-02-02
  • C++头文件algorithm中的函数功能详解

    C++头文件algorithm中的函数功能详解

    这篇文章主要介绍了C++头文件algorithm中的函数功能详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • 简单了解C++语言中的二元运算符和赋值运算符

    简单了解C++语言中的二元运算符和赋值运算符

    这篇文章主要介绍了C++语言中的二元运算符和赋值运算符,文中列出了可重载的运算符列表,需要的朋友可以参考下
    2016-01-01

最新评论