1.预定义符号
下面的预定义符号都是语言内置的,我们可以直接使用
__FILE__//进行编译的源文件
__LINE__//当前行号
__DATE__//文件被编译的日期
__TIME__//文件被编译的时间
举个例子,打印当前文件被编译的日期和时间:
int main() { printf("%s %s",__DATE__,__TIME__); return 0; }
2.#define
#define定义标识符
语法:
#define name stuff
1
如:
#define MAX 1000 #define Peo Peoinfo
1
2
在程序中,可以直接使用这些标识符,举个例子:
#define MAX 1000 #define Peo Peoinfo int main() { int Peo = MAX; }
要注意一点:
在define定义时,不要在最后加上;
#define MAX 1000;//在后续运行中会出现错误 #define MAX 1000//正确写法
1
2
在定义标识符时,如果像一下定义,会出现问题
#define A 1+3 #define B 4+3 int main() { int c = A*B; }
这里如果我们主观上会认为A就是1+3的值为4,B是4+3的值为7,所以在后面的替换后,int c = A*B替换成int c = 4*7,c的值就是28,其实这是错误的
在预处理中的替换是“直接替换”,预处理后int c = A*B会变为int c = 1+3*4+3,由于运算符有优先顺序,c的为16.
#define定义宏 #define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
宏的申明方式如下:
#define name( parament-list ) stuff 1
parameter-list为参数列表,参数会出现在stuff中
注意:
参数列表的左括号必须与name紧邻,中间不能有空格
如果之间有空格存在,参数列表就会被解释为stuff中的一部分
接下来举一个例子
定义一个宏,这个宏接收一个参数x
#define SQUARE(x) x*x
1
将宏声明之后,在预处理中,例如SQUARE(5)就会被5*5所替换
#define SQUARE(x) x*x int main() { int num = SQUARE(5); printf("%d",num);//结果会输出5 } 1
面代码:
#define SQUARE(x) x*x int main() { int num = SQUARE(1+5); printf("%d",num); }
,可能会认为这段代码打印结果是36,但事实上这个程序打印11
因为在替换文本时,参数x被替换成了1+5,所以语句变成了int num = 1+5*1+5
所以可以看出,由替换产生的表达式并没有按照预想的次序进行求值
其实在宏定义时,加上两个括号就可以解决这个问题
#define SQUARE(x) (x)*(x)
1
在预处理之后替换成:int num = (1+5)*(1+5)
继续观看一下代码:
#define SUM(x) (x)+(x) int main() { printf("%d",10*SUM(5)); }
这个代码仍有问题
在预处理后会替换成:
printf("%d",10*(5)+(5)); 1
可以看出,由于表达式的优先次序,这个宏不会按照我们的想法进行正确计算
所以宏定义表达式两边加上一对括号就可以了
#define SUM(x) ((x)+(x)) 1
用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中
的操作符或邻近操作符之间不可预料的相互作用。
#define 替换规则
在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
#和##
#的作用是
把宏的参数插入到字符串中
首先我们先看一个代码:
printf("hello ""world"); 1
我们将"hello world"分写成2个字符串,运行代码后,仍然输出hello world
所以可以看出字符串是有自动连接的特点的
再看一个代码:
int main() { printf("the size of int is %d\n", sizeof(int)); printf("the size of char is %d\n", sizeof(char)); printf("the size of short is %d\n", sizeof(short)); printf("the size of float is %d\n", sizeof(float)); printf("the size of double is %d\n", sizeof(double)); return 0; }
如果我们想要计算每个类型的大小,并且要同字符串一块打印出来,每打印一次都需要写一段字符串,而且字符串中的要写的类型还不同,十分麻烦
所以我们可以使用宏
所以可以在定义宏时,通过使用#,把参数插入字符串中
#define PRINT(type,size) printf("the size of " #type" is %d\n",size) 1
所以在使用宏时,就十分方便
int main() { PRINT(int, sizeof(int)); PRINT(char, sizeof(char)); PRINT(short, sizeof(short)); //…………………………………………………… return 0; }
##的作用是:
##可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符。
观察一下代码:
#define COMBINE(x,y) x##y int main() { int abcd = 10; printf("%d\n", COMBINE(ab, cd));//结果输出10 return 0; }
通过使用宏,##将x和y合成一个符号,在预处理后语句变为:printf("%d\n",abcd);
注意:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。