#define的定义范围
#define不光可以定义变量,常量,还可以定义几乎所有的东西,因为#define可以定义一串代码(即宏),所以包含在代码中的东西都能被定义。
#define定义宏
定义是宏名必须于它的参数括号紧挨,中间不能有任何符号,空格都不行。
向宏中传参的时候是直接把传进去的参数直接替换,而不是先计算表达式再传参。
所以如果你的参数只有一个,但你却传了一个表达式,他会把这个表达式直接替换进去,这个时候如果不加括号,肯定就会出现错误。
例
因为*的优先级大于+,所以他得到的结果不是36,而是11。
此时加上括号就可以解决
即 square(x) (X)*(X)
其实光给X打括号还不够安全
例
我们想要的来是,3传进去得到6,6在与10相乘得到60
但其实实际得到的结果是33。
此时如果在在两个x的后打一个包括两个X的括号,就可以解决。
即 square(x)((X)*(X))
所以为了安全,尽量给宏的参数和整个宏的内容都打上括号。
#define替换规则
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
宏参数和#define定义中可以出现其他#define定义的符号。
但是对于宏,不能递归。
当预处理器搜索#define定义的符号的时候,字符串中的内容并不被搜索和改变。
宏的内容中的#的作用
的作用是,放在参数的前面
可以将传进来的参数变成对应的字符串。
例 假设传进去的参数是abcd,如果你在宏的内容中的参数前加了#,他就会被修改为"abcd"
宏中的##的作用
将##两边的符号合成一个符号,但是合成之后的符号必须是定义过的
例:如果宏中有sum##a,在执行程序的时候,sum##就相当于suma被使用
##也可以放在宏参数和宏参数之间或者宏参数和符号之间
例
带副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
例
上图的宏参数传了a++和b++,传入了MAX后的代码相当于106行写的代码。
可以看到a和b都在宏中被多次赋值,得到的结果,可能不是我们想要的结果。
而且宏不像函数传值调用时函数调用结束后不改变实参,
宏调用之后不管你是传值还是传地址,传入的参数只要在宏中改变了,宏调用结束后,实参也会被改变。
所以MAX调用结束后m的值为6,a的值为7,b的值为5
所以使用宏时参数尽量不要使用有副作用的参数。
宏对于函数的优缺点
优点:
1.因为宏是在预处理的时候就编译了,运行的时候不用再编译,只需要执行计算就可以,所以用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
2.更为重要的是函数的参数必须声明为特定的类型,而宏不用
所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。
缺点:
1.每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2.宏是没法调试的。
3.宏由于类型无关,也就不够严谨。
4.宏可能会带来运算符优先级的问题,导致程容易出现错。
5、宏不能递归。