目录
三、 预处理详解:
3.1 预定义符号:
所谓预定义符号,即指:在预处理阶段被处理的,已经定义好的符号,可以直接拿来进行使用、
这些预定义符号都是语言内置的。
__FILE__ //打印出正在进行编译的源文件的文件名 ——— %s、
__LINE__ //打印该代码当前所处的行号 ——— %d、
__DATE__ //文件被编译的日期 ——— %s、
__TIME__ //文件被编译的时间 ——— %s、
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义 ——— %d、
//VS编译器不支持该标准,而Linux系统下的gcc编译器支持该标准、
例如:
所以,由此可知,VS编译器不支持循ANSI C标准,而Linux系统下的gcc编译器是支持循ANSI C的,并且,得到的值是1、
作用:当工程特别复杂的时候,在代码运行中记录一些日志信息,当运行出现错误的时候,可以通过记录的日志信息来排查错误,写日志
就是在写文件、
比如:
3.2 #define:
作用:定义符号(标识符)和宏、
3.2.1 #define 定义标识符(符号):
语法:
#define name stuff
#define 定义的符号不一定只能是数字,只要满足语法要求即可、
比如:
#define MAX 1000
#define REG register //为 register这个关键字,创建一个简短的名字、
#define DO_FOREVER for(;;) //用更形象的符号来替换一种实现,死循环、
#define CASE break;case //在写case语句的时候自动把 break 写上、
// 如果定义的 stuff 过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )
#define MAX 1000;
#define MAX 1000
部分情况下是可以加上的,加上之后语法也是正确的,比如:
但是在某些情况下,加上分号之后,语法就是错误的,比如:
所以,当 #define 定义标识符的时候,尽量不要带上分号; 在某些情况下容易出现语法错误、
3.2.2 #define 定义宏 :
#define name( parament-list ) stuff

拓展1:
由替换产生的表达式并没有按照预想的次序进行求值、改进:
总结:在写宏的时候,不要吝啬括号,括号的作用非常重要、
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预
料的相互作用。
拓展2:
改进:
3.2.3 #define 替换规则 :
#include<stdio.h>
#define M 100
#define MAX(X,Y) (((X)>(Y))?(X):(Y))
int main()
{
int max = MAX(101, M);
//在完成宏的替换之前,先检查宏的参数,如果有#define定义的符号,先替换该符号,把所有的#define定义的符号替换完成后再替换宏,最后再次检查,如果再有#define定义的
//符号的话,重复上述过程、
//由上面可知,宏的参数中有#define定义的符号M,先进行替换,得到: int max = MAX(101, 100);
//再进行宏的替换,得到: int max = (((101)>(100))?(101):(100));
//#define定义的符号和宏都是在预处理阶段进行完成的、
return 0;
}

3.2.4 #和##:
# 和 ## 只能在宏内部使用,不是直接拿宏的参数去替换文本,而是把参数中的内容转化成对应的字符串的形式再放在文本中、
当使用 printf 打印两个字符串的时候,处理的方式和一个字符串是一样的,两个字符串天然的会连接在一起,无论其两者中间有多少个空格
都不影响结果、 字符串是有自动连接的特点的、
错误示范:
改正:
拓展:
## 的作用 :
把两个符号连接成一个符号,也可以把多个符号连接成一个符号,即把两端的符号连接形成一个整体、

3.2.5 带副作用的宏参数:
何谓副作用,此处所讲的副作用即指,比如:
#include<stdio.h>
int main()
{
int a = 1;
int b = a + 1;
//上述代码结果中,a=1,,b=2,,,就称上述代码没有副作用、
int a = 1;
int b = ++a;
//上述代码最后的结果中,a=2,,b=2,,此时,a要自增一下,就称之为具有副作用、
return 0;
}
如果宏的参数部分带有副作用,即:
//答案应该是多少呢?
#include<stdio.h>
#define MAX(X,Y) ((X)>(Y)?(X):(Y))
int main()
{
int a = 5;
int b = 8;
int m = MAX(a++, b++);//宏的参数带有副作用、
printf("m=%d\n", m);// ?
return 0;
}
带有副作用的宏参数,尽量避免使用,当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就
可能出现危险,导致不可预测的后果,副作用就是表达式求值的时候出现的永久性效果、
x+1;//不带副作用
x++;//带有副作用
3.2.6 宏和函数对比:
#define MAX(a, b) ((a)>(b)?(a):(b))
4、 宏可能会 带来运算符优先级的问题 ,如果宏的参数不是一个变量而是一个 表达式 ,在宏参替换宏体内容的时候,如果宏体内有多种操作符的
一、使用宏来运算该简单的任务:
其汇编代码只有以下这些:
宏的两个参数是完全替换的,替换之后只要能够使用大于号进行比较就行,所以即使是其他类型,只要能够使用 > 进行比较,就满足要求,
比如两个浮点型进行比较,两个整型进行比较,只要替换掉的两个值能够使用大于号进行比较都是可以的,宏的参数是没有类型检查的,所
以用宏进行运算的话,可以比较多种类型的数据,而使用函数运算的话,只能比较一种固定类型的数据,所以在处理一些简单的问题上,使
用宏进行运算比使用函数要具有较多的优点,但是在一些运算比较复杂的情况下,使用函数进行运算比使用宏进行运算会更加方便、
二、使用函数来运算该简单的任务:
其汇编代码有:
由上图可知,为了实现两个数真正的比较过程,要进行大量的准备工作,同时当两个数比较完大小之后还要为调用函数的返回过程做准备,
所以,使用函数的方法来进行比较简单的运算的时候,真正比较大小前的准备工作和调用函数返回过程的工作量可能比进行两个数的比较的
工作所需要花费的时间更多,除此之外,函数的形参部分能够接收到的数据的类型是固定的,在此代码中,只能用来比较两个整型int类型的
数据,不能用来比较两个其他类型数据的大小,由于字符类型也属于整形家族,所以还可以用来比较两个字符的大小,只不过可能会报警
告,类型有所差异、
宏有时候可以做函数做不到的事情,比如:宏的参数可以出现类型,但是函数做不到、 还有就是,宏体内部的#和##的使用,函数也是做不到
的、
#include<stdio.h>
//在定义宏的时候,宏名最好写成全部大写,宏的参数可以写成小写、
#define MALLOC(num,type) (type*)malloc(num*sizeof(type))
int main()
{
int* p = (int*)malloc(10 * sizeof(int));
//这样来动态开辟内存空间时,malloc函数参数中的10*sizeof(int),书写起来比价麻烦,能否写成: int* p = (int*)malloc(10,int);
//答案是不行的,函数是不支持这样进行传参的,要知道,malloc是一个函数,函数传参的时候,不能使用类型去传参,可以传值,传变量,
//但是不可以传类型,所以就可以使用宏来完成这件事情,这是函数所做不到的、
int* p = MALLOC(10, int);
//这就是所谓的宏的参数中可以出现类型的情况,这是函数所做不到的、
//预处理替换后得到的是: int*p=(int*)malloc(10*sizeof(int))
return 0;
}
总结:如果一个运算的过程比较简单,则可以使用宏进行运算,因为简单,写宏的时候不容易出现错误,速度更快,效率更高,如果一个运算的
过程比较复杂,则最好写成函数的形式,结果容易把控,在C99之后引入了内联函数(inline)的概念,它结合了宏和函数的优点,在C++中会具
体涉及到、
3.3 预处理指令 — #undef :
#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
比如:
总结:
对于预处理指令 #define 和 #undef 来说,他们不考虑 局部和全局,只考虑该预处理指令所在的代码行、
对于预处理指令#define来说:
对于预处理指令#define定义的符号来说,在该预处理指令所在的代码行往下的所有的区域都可以使用该符号、
对于预处理指令#undef来说:
它通常情况下是在预处理指令#define后面进行使用,如果在预处理指令#define前面或者单独使用预处理指令#undef都是不起作用的,只有在预
处理指令#define后面使用#undef的时候,才能起到有效的作用,在此只考虑正常的情况,那么预处理指令#undef起作用的范围就是在该指令所在
的代码行往下的所有区域内、