义乌做网站的,百度浏览器极速版,网站建站网站 小说,菜户营网站建设公司在严格意义上的编译过程开始之前#xff0c;C语言预处理器首先对程序代码做了必要的转换处理。预处理器的主要作用是#xff1a;
我们有时需要将某个特定数量在程序中出现的所有实例统统加以修改大多数C语言实现在函数调用时都会带来重大的系统开销
1. 不能忽视宏定义中的空…在严格意义上的编译过程开始之前C语言预处理器首先对程序代码做了必要的转换处理。预处理器的主要作用是
我们有时需要将某个特定数量在程序中出现的所有实例统统加以修改大多数C语言实现在函数调用时都会带来重大的系统开销
1. 不能忽视宏定义中的空格
#define f (x) ((x)-1)
此时f(x)代表
(x)((x)-1)
如果希望定义f(x)为((x)-1)必须这样写
#define f(x) ((x)-1)
空格的规则适用于宏定义但是不适用于宏调用所以f(3)和f (3)的结果都等于2 2. 宏并不是函数
宏定义中出现的所有括号它们的作用时预防引起与优先级有关的问题如果没有括号求绝对值的定义如下
#define abs(x) x0?x:-x
此时abs(a-b)求值的结果将是
a-b0?a-b:-a-b
-a-b与我们期望的-(a-b)是不一样的。
正确的实现应该是
#define abs(x) ((x)0)?(x):-(x))
即使宏定义中的各个参数与整个结果表达式都被括号括起来也仍然还可能有其他问题存在比如说一个操作数如果在两处被用到就会被求值两次。比如
biggestmax(biggest, x[i]);
在宏展开后将会变成
biggest((biggest)(x[i])?(biggest):(x[i]));
i可能被执行两次导致错误解决这个问题的办法
确保max中参数没有像--这样的副作用将max使用函数实现
使用宏的另外一个危险是宏展开可能产生非常庞大的表达式占用空间远远超过编程者所期望的空间比如 3. 宏并不是语句
assert宏的一个错误实现
#define assert(e) if (!e) assert_error(_FILE_, LINE_)
但这样会导致一些错误 这个修复方式是把宏体整个括起来即如下
#define assert(e)\{if (!e) assert_error(__FILE__, __LINE__);}
但是这样会带来新的问题上面的例子展开后如下
if(x 0 y 0){if(!(x y)) assert_error(foo.c, 37);};
else{if(!(y x)) assert_error(foo.c, 39);};
在else之前的分号是一个语法错误。因此assert宏的正确实现如下
#define assert(e) \((void)((e)||_assert_error(__FILE__,__LINE__)))
另外一个实现如下
#define assert(expression) \((void)((expression) || \(printf(Assertion failed: %s, file %s, line %d\n, \
#expression, __FILE__, __LINE__), abort(), 0)))
4. 宏并不是类型定义
宏的一个常见用途是使多个不同变量的类型可在一个地方说明宏定义的这种用法有一个优点——可移植性。但是用宏定义类型会有一些问题还是推荐使用typedef关键字
#define T1 struct foo *
typedef struct foo *T2T1 a,b;
T2 a,b;
其中T1 a,b将被扩展为
struct foo * a, b;
这个语句中a被定义为一个指向结构的指针而b却被定义为一个结构而不是指针。