程序环境和预处理

目录

1. 程序的翻译环境和执行环境

2. 详解编译+链接

3.运行环境

4.预处理

         1 预定义符号

2.#define 定义标识符

3.续行符

4.#define定义宏

         5.宏替换规则


1. 程序的翻译环境和执行环境

翻译环境:在这个环境中源代码被转换为可执行的机器指令。

执行环境:它用于实际执行代码。

2. 详解编译+链接

首先我们看一张图:

程序环境和预处理_第1张图片

在一个工程中,我们需要协作,那必须创建多个源文件(test.c),那么每个源文件经过编译器编译变为test.obj,再由链接器加链接库把test.obj文件变为test.exe可执行文件。 

接下来,我们具体看过程:

其实笼统地来说,由.c文件到.exe文件,只有两步,编译和链接,但是细分的话,有四步:

程序环境和预处理_第2张图片程序环境和预处理_第3张图片 

程序环境和预处理_第4张图片

 所以仔细看图以后,我们可以知道,其实到可执行文件有四步,预处理,编译,汇编,链接。

编译过程中符号汇总,汇编产生的符号表,以及后面链接时要进行的符号表的合并和重定位。

都是非常重要的。

3.运行环境

程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用 main 函数。( 程序的入口)
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static )内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止 main 函数;也有可能是意外终止。

4.预处理

1 预定义符号

__FILE__       // 进行编译的源文件
__LINE__     // 文件当前的行号
__DATE__     // 文件被编译的日期
__TIME__     // 文件被编译的时间
__STDC__     // 如果编译器遵循 ANSI C ,其值为 1 ,否则未定义
printf ( "file:%s line:%d\n" , __FILE__ , __LINE__ );可以通过打印字符串的方式来显示。

2.#define 定义标识符

#define +标识符+符号内容
(注意的一点是,#define定义标识符最后尽量不要加;(分号),因为会将分号当作标识符内容一起替换掉。)
比如:
#define MAX 1000;
#define MAX 1000


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

为了防止分号多出现这种情况,尽量不要加;。

 3.续行符

如果定义的 stuff 过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠 ( 续行符 )
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
                         date:%s\ttime:%s\n" ,\
                         __FILE__,__LINE__ ,\
                         __DATE__,__TIME__ )  

其实相当于\转义了回车,当内容太长的时候,就可以利用续行符来解决,其实是在同一行。

4.#define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义
宏(define macro)。
下面是宏的申明方式:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
举例说明:
#define square(x) ((x)*(x))

int main()
{
  int a=5;
  square(a+1);
}

会换成:
((5+1)*(5+1))

在写宏时,不要吝啬括号,能加括号的地方就加括号,会防止很多运算符优先级打乱预期的结果。

#define square(x) x*x

int main()
{
  int a=2;
  Add(a+1);
}

会换成:
2+1*2+1

程序环境和预处理_第5张图片

从而没有到达我们平方的预期。

 5.宏替换规则

在程序中扩展 #define 定义符号和宏时,需要涉及几个步骤:
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由 #define 定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由 #define 定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和 #define 定义中可以出现其他 #define 定义的符号。 但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

你可能感兴趣的:(C中难点,开发语言,后端)