程序环境的预处理

简介: 本章重点:程序的翻译环境程序的执行环境详解:C语言程序的编译+链接预定义符号介绍:预处理指令 #define宏和函数的对比预处理操作符#和##的介绍命令定义预处理指令 #include预处理指令 #undef条件编译


本章重点:

程序的翻译环境

程序的执行环境

详解:C语言程序的编译+链接

预定义符号介绍:

预处理指令 #define

宏和函数的对比

预处理操作符#和##的介绍

命令定义

预处理指令 #include

预处理指令 #undef

条件编译


提示:以下是本篇文章正文内容,下面案例可供参考


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

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

在ANS1C的任何一种实现中,存在两个不同的环境。


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


2、详解编译+链接

翻译环境


组成一个程序的每个源文件通过编译过程分别转换成目标代码(obiect code)。

每个目标文件由链接器( linker )捆绑在一起,形成一个单一市完整的可执行程序。

链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。


3、编译本身也分为几个阶段:



4、如何查看編译期间的每一步发生了什么呢?

代码如下;




1、预处理 选项 gCC -E test.c-o rest.i预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

2、编译选项 gcc -5 test•<编泽完成之后就停下来,结果保存在test.s中。

3、汇编 gcE c test.c 汇编完成之后就傳下来,结果保仔在test,o中。


二、运行的环境

5、运行环境

程序执行的过程;


1.程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。


2程序的执行便开始。接着便调用main函数。


3.开始执行程序代码。这个时候程序将使用一个运行时堆栈 (stack),存储西数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。


4.终止程序。正常终止main函数;也有可能是意外终止。


6、预处理详解

预定义符号


#define




7、#define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro )


下面是宏的申明方式:


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


注意:参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuf的一部分。


如:


#define SQUARE( x)


这个宏接收—个参数x . 如果在上述声明之后,你把


SQUARE( 5 );


置于程序中预处理器就会用下面这个表达式替换上面的表达式:

5*5


警告:


这个宏存在一个问题:观察下面的代码段:


inta =5;

printf(“%din” , SQUARE( a + 1) );


乍一看,你可能觉得这段代码将打印36这个值。事实上,它将打印11.为什么?


替换文本时,参数x被著换成a+1所以这条语向实际上变成了:prirtf q"gfclirma+1*a+1)


这样就比较清晰了,由替换产生的表达式并没有按照预想的次序进行求值,


在宏定义上加上两个括号这个问题便轻松的解決了。


#define SQUARE(x)×*(x)


这样预处理之后就产生了预期的效果


printf (“%d\n”, (a + 1) *(a+1):


这里还有一个宏定义:

#define DouBLE(x)( x )+(x)


定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。


int a = 5:

printf(“%d\n” .10 * DOUBLE(a)) :


这将打印什么值呢?

warning :看上去,好像打印100,但事实上打印的是55.我们发现替换之后:


printf (“%d\n”, 10 * "(5) + (5)) :


乘法运算先于宏定义的加法,所以出现了

55


这个问题,的解決办;法是在宏定义表达式两边加上一对括号就可以了。


#de Fine DoUBLEC x (x)+(6x)


提示:


所以用干对数信表达式进行求值的宏定义都应该用这种方式加上括号.避免在使用宏时由千参数中的操作符或邻近操作符之间不可预料的相互作用。


8、#define 替换规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤;


1、在在调用宏时,首先对参数进行检查 ,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。

2、替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换

3、最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。


注意:


1.宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。


2.当预处理器搜索#define定义的符号的时候 ,宇符串常量的内容并不被搜索:


#和##

如何把参数插人到字符串中?


首先我们看看这样的代码:




9、##的作用

##可以把位于二两边的符号合成一个符号,区升许宏义从分高的文本片段创建标识符。

注:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。


带副作用的宏参数


当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,


致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。


例如:

x+1;//不带副作用

x++;//带有副作用


总结

这里对文章进行总结:

以上就是今天要讲的内容,本文仅仅简单介绍了程序环境的使用,而程序环境提供了大量能使我们快速便捷地处理数据的方法。

————————————————


相关文章
|
4月前
|
存储 自然语言处理 程序员
程序环境和预处理(1)
程序环境和预处理(1)
36 0
|
5月前
|
存储 编译器 程序员
零基础也能学会的『程序环境和预处理』
零基础也能学会的『程序环境和预处理』
|
5月前
|
存储 自然语言处理 编译器
程序环境和预处理(详解)
程序环境和预处理(详解)
|
存储 编译器 程序员
【C】程序环境和预处理
在ANSI C的任何一种实现中,存在两个不同的环境。
|
编译器 Linux C++
【程序环境与预处理】(二)
【程序环境与预处理】(二)
81 0
|
存储 自然语言处理 程序员
【程序环境与预处理】(一)
【程序环境与预处理】(一)
79 0
|
5月前
|
编译器 Linux C++
【程序环境与预处理玩转指南】(下)
【程序环境与预处理玩转指南】
|
5月前
|
存储 编译器 程序员
【程序环境与预处理玩转指南】(上)
【程序环境与预处理玩转指南】
|
5月前
|
存储 自然语言处理 编译器
程序环境+预处理
程序环境+预处理
70 0
|
10月前
|
存储 自然语言处理 编译器