关于C语言中程序的预编译,编译,汇编以及链接

C语言中,一段代码的执行,需要经过编译和链接两个步骤,其中编译阶段又是分为三步来完成的,分别是:预编译,编译,汇编。所以说,一段代码写出来到执行,一共经历了预编译,编译,汇编,链接四个步骤。但底层其实做了更多的事情,这里就不说那么细了,因为我也不知道,哈哈哈哈哈,想要多了解的话,可以去看看《编译原理》这本书。今天的分享内容主要是预编译阶段,其他的几个阶段都只是稍稍提及一下。

1、预编译阶段

在预编译阶段呢,编译器会将一些预处理符号进行一些替换。说到预处理符号,就有必要深入讲解一下了:

#include

在学习C语言的开始,我们就知道,要在屏幕上打印一些东西,就要引入一个头文件叫 stdio.h ,那么引入头文件这个动作:

#include 

就是预处理操作, #include 就是一个预处理符号,在编译器对这段代码进行预编译的时候,会将头文件 stdio.h 中的所有内容都引入到我们自己所写的这个文件中,然后删除这个预编译指令。

例如:

#include 

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

我们在linux中用gcclai对这段代码进行预编译:

使用命令:gcc test.c -E -o test.i

意思是对test.c进行预编译,将预编译的结果输出到test.i 这个文件中。

关于C语言中程序的预编译,编译,汇编以及链接_第1张图片

 可以看到,#include被替换成了stdio.h文件中的内容。

那么,这就引出了一个问题,如果一个头文件被重复引两次,内容会不会被重复的替换两次呢。

#include 
#include 

答案是会的。那在一些大型的项目中,各个模块是有不同的人员进行负责的,最后进行模块的组合,那样的话,这种头文件的重复引用就很难避免。

这种问题要怎么解决呢:

其实有一些条件预处理符号:

#ifudef 如果未定义后面的表达式那就会执行这个条件预处理符号下面的代码

#define 定义一个常量或者宏

#endif 结果条件预处理符号

这三个预处理符号在一起就会碰撞出火花,可以通过这三个预处理符号的组合,来防止头文件的多次引入:

#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif   //__TEST_H__

除了这三个预处理符号的结合,可以对头文件的多次引入进行预防外,还有一个预处理符号,可以有这个作用:

#pragma once

如果使用vs的小伙伴,看见这个就一定很眼熟,没错,在新创建一个头文件的时候,就会自动出现这行代码,可能之前有的小伙伴不知道这是什么意思,那相信看完到这就明白了。

那么除了这个,还有那些是预处理符号:

#define

#define name  stuff

#define可以定义常量和宏,然后,他们会在与编译阶段进行内容的替换:

#define MAX 1000
#define reg register          //为 register这个关键字,创建一个简短的名字 
#define do_forever for(;;)     //用更形象的符号来替换一种实现
#define CASE break;case        //在写case语句的时候自动把 break写上。

首先来看看常量的替换:

#include 
#define MAX 100

int main(){
    int a = MAX;
    return 0;
}

进行预编译:

关于C语言中程序的预编译,编译,汇编以及链接_第2张图片

 可以看到,在预编译阶段,用#defien 定义的常量就会被替换,需要注意的是,用 #define 定义的常量后有标点符号的话,在替换的时候,也会被替换上去。有时候会出现不知名的错误。

用 #define 定义宏,

#define name( parament-list ) stuff 其中的 parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中。

#define SUM(x,y) ((x)+(y))

定义一个宏,使用一下:

int main(){
    printf("%d\n", SUM(3,4));
}

注意,在定义宏的时候,一定要带上尽可能多的括号,因为,宏的使用存在很多不确定因素,比如宏的定义,会和被宏替换的表达式产生别的计算顺序;或者传值的时候给宏传入的是a++,这些会产生连锁反应的表达式……

编译阶段

将c语言代码编译成汇编代码

汇编阶段

将c语言编译成二进制代码

链接阶段

链接阶段,会将每个文件中的符号(函数名)收集起来,放到一个符号表中,在连接阶段,会将相关的各个文件的符号表对应起来,如果有找不到的符号,那就会报错,报的错误是链接错误,找不到某个函数,其实就是符号表中,没找到该有的函数名。

好了,今天的分享就到这了。

你可能感兴趣的:(c语言,汇编,开发语言)