打印

宏定义

[复制链接]
2424|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
醉心369|  楼主 | 2012-12-18 22:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
沙发
john_lee| | 2012-12-18 23:09 | 只看该作者
那个所谓“正确的用法”也是不对(有缺陷)的。

使用特权

评论回复
板凳
ayb_ice| | 2012-12-19 07:58 | 只看该作者
本帖最后由 ayb_ice 于 2012-12-19 16:01 编辑

一行不够写,下一行接着写

使用特权

评论回复
地板
ver军| | 2012-12-19 14:39 | 只看该作者
文本编辑时留下的,和代码本身没联系

使用特权

评论回复
5
coody| | 2012-12-19 15:04 | 只看该作者
分行写宏就是这样。宏最后一般不要加分号。

使用特权

评论回复
6
醉心369|  楼主 | 2012-12-19 15:45 | 只看该作者
john_lee 发表于 2012-12-18 23:09
那个所谓“正确的用法”也是不对(有缺陷)的。

哪里有缺陷啊,正确的是什么啊

使用特权

评论回复
7
醉心369|  楼主 | 2012-12-19 15:46 | 只看该作者
ayb_ice 发表于 2012-12-19 07:58
一行够写,下一行接着写

是一行不够写吧

使用特权

评论回复
8
ayb_ice| | 2012-12-19 16:01 | 只看该作者
醉心369 发表于 2012-12-19 15:46
是一行不够写吧

不好意思,笔误

使用特权

评论回复
9
lu50211| | 2012-12-19 16:14 | 只看该作者
什么情况!

使用特权

评论回复
10
lzqxs89| | 2012-12-19 16:34 | 只看该作者
john_lee 发表于 2012-12-18 23:09
那个所谓“正确的用法”也是不对(有缺陷)的。

希望版主能够解析下什么地方有缺陷。

使用特权

评论回复
11
lzqxs89| | 2012-12-19 16:35 | 只看该作者
john_lee 发表于 2012-12-18 23:09
那个所谓“正确的用法”也是不对(有缺陷)的。

是不是a、b的类型问题啊?

使用特权

评论回复
12
john_lee| | 2012-12-19 16:49 | 只看该作者
本帖最后由 john_lee 于 2012-12-19 16:51 编辑
醉心369 发表于 2012-12-19 15:45
哪里有缺陷啊,正确的是什么啊


先来看一个例子:
if (condition)
    INTI_RECT_VALUE(ret[index].a, rect[index].b);
else
    ...
其中的 INTI_RECT_VALUE 宏是抄你的,else 后面的语句具体是什么无关紧要,重要的是有个 else。
这段程序编译会产生一个错误:error: 'else' without a previous 'if',这是 gcc 编译器的报错,其它编译器的报错可能稍有不同,但意思一样。

问题的根本,在于单条语句复合语句的区别,单条语句要求以分号“;”结束,而复合语句则是由大括号“{}”包围,如果我们在复合语句结束的大括号之后加一个分号:
{ a = 0; b = 0; }; // 注意最后的分号,它绝非无关紧要
我稍微把上面的语句变形一下,拆成两行:
{ a = 0; b = 0; }
;
第1行是一个复合语句,而第2行的那个单独的分号,按C语法来说,是一个空语句,注意,它确实是一条语句。就是说在复合语句后加一个分号,实际上是两条语句
在一般顺序执行的语句逻辑中,多一个几个空语句是无害的,但在条件分支语句(if)中,不允许有多条语句:
if (condition)
    statement1
else
    statement2
如果在 if (condition) 后出现了两条语句,按语法来说,第2条语句就自动结束了 if 语句,如果其后再出现 else,编译器只能报错了。

解决这个问题的方法,有两个:
1、始终在 if 语句中加入大括号,这样可以保证只有一个复合语句在其中,这个方法要求编程者主动配合,而不是从语法层面堵死漏洞,显然不能让人满意。
2、把宏定义的复合语句变形为单条语句,使之完全符合语法要求,具体做法是,在原来定义的复合语句的前面(“{”之前),加一个“do”,在后面(“}”之后)加一个“while (0)”:
#define INTI_RECT_VALUE(a, b)     \
    do {                          \
        a = 0;                    \
        b = 0;                    \
    } while (0)
注意“while (0)”后面没有分号,在宏调用展开时,原来宏后面的那个空语句分号,将把“while (0)”后面的分号补上,使之成为一个单条语句,展开后的结果:
if (condition)
    do {
        ret[index].a = 0;
        ret[index].b = 0;
    } while (0);
else
    ...

使用特权

评论回复
13
bruceding| | 2012-12-19 17:07 | 只看该作者
续行符  楼上正解    其实用,运算符也不错 如下
#define INTI_RECT_VALUE(a, b)    a = 0, b = 0
  

使用特权

评论回复
14
jack821119| | 2012-12-19 17:10 | 只看该作者
其实也不用那么复杂,简单点就可以了.如下:
if (condition)

INTI_RECT_VALUE(ret[index].a, rect[index].b)

else
......


使用特权

评论回复
15
refee| | 2012-12-19 17:20 | 只看该作者
12楼解释得很好 很详细 :handshake

使用特权

评论回复
16
醉心369|  楼主 | 2012-12-19 18:15 | 只看该作者
john_lee 发表于 2012-12-19 16:49
先来看一个例子:其中的 INTI_RECT_VALUE 宏是抄你的,else 后面的语句具体是什么无关紧要,重要的是有个 ...

版主,你讲的非常详细。13的宏定义是否可行?

使用特权

评论回复
17
john_lee| | 2012-12-19 18:55 | 只看该作者
13楼的宏定义方法,使用了逗号运算符,而逗号运算符的两边都要求是表达式,所以这种方法有个局限:只适合可以构成表达式的语句,例如 a = 0 和 b = 0 均是表达式,而其它非表达式的语句就无能为力了,比如 if for while 等语句。

使用特权

评论回复
18
john_lee| | 2012-12-19 19:04 | 只看该作者
14楼的方法不可取,因为这个宏看起来就像是一个单条语句,一般写程序都习惯地认为单条语句后就应该加分号结束,这种方法与习惯相左,你自己写自己用倒无所谓,怕的就是让别人来使用你的宏,还要让别人记住你这个宏的特殊性,显然会被吐槽的。

记住,规则定义要尽量统一且符合习惯用法。

使用特权

评论回复
19
醉心369|  楼主 | 2012-12-19 22:00 | 只看该作者
学习了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

60

主题

283

帖子

2

粉丝