运行环境
- 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序
的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。 - 程序的执行便开始。接着便调用main函数
- 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回
地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程
一直保留他们的值。 - 终止程序。正常终止main函数;也有可能是意外终止。
预处理讲解
下面是代码的实现
#define 定义标识符
一
/#define do_forever for(;;)
//
//int main()
//{
// do_forever;
// return 0;
//}
预处理会把for(;;)替换do_forever造成死循环
二
在define定义标识符的时候,要不要在最后加上 ; ?
#define MAX 1000;
max = MAX;替换会产生重复
#define 定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
#define SQUARE( x ) x * x, SQURE是函数1名字,括号内是参数。而且括号必须和函数挨在一起,括号外侧就是内容如下图
在预处理阶段就完成替换
替换说明
#define DOUBLE(x) (x) + (x)
int a = 5;
printf(“%d\n” ,10 * DOUBLE(a));
看上去,好像打印100,但事实上打印的是55.
我们发现替换之后:
printf (“%d\n”,10 * (5) + (5));
这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。
这个替换是直接替换,而非计算完之后替换过去
define 替换规则
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先
被替换。 - 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
- 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上
述处理过程。
注意: - 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
- 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。printf(“hehe M”)这里的M就不会被宏所替换
#和##
使用 # ,把一个宏参数变成对应的字符串
int i = 10;
#define PRINT(FORMAT, VALUE)\
printf("the value of " #VALUE “is “FORMAT “\n”, VALUE);
PRINT(”%d”, i+3);
最终的输出的结果应该是
the value of i+3 is 13
带副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能
出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
int m = MAX(6, 3);
int a = 4;
int b = 6;
int m = MAX(a++, b++);
//int m = ((a)>(b)?(a):(b));
// 4 > 6 7
//int m = Max(a++, b++);
printf("%d\n", m);//7
printf("a=%d b=%d\n", a, b);//5 8
return 0;
宏的作用是替换,不是传递参数。
宏和函数对比
#define MAX(a, b) ((a)>(b)?(a):(b))
- 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
- 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的