我无法评论答案本身,所以:关于Using comma to prevent the need for brace pair
#define MY_ASSERT(expr) ((expr) || (debugbreak(), 0))
这里debugbreak()返回void,但我们仍然希望将0作为右值。
(debugbreak(),0)如何返回0?我知道debugbreak()的返回值被丢弃并且返回0,但是debugbreak会生成异常,那么之后如何评估任何内容呢?我想我的问题可以推广到任何类似的二元运算符,其中被评估的第一部分退出程序。
答案 0 :(得分:4)
这是一种类型系统黑客。
#define MY_ASSERT(expr) ((expr) || (debugbreak(), 0))
// note the or operator here ^
||
运算符采用两个bool
- 类型(或可转换)表达式。 debugbreak()
是void
- 已键入。要使其bool
,请使用以下规则:
(FOO, BAR)
// ^ determines the type of the entire comma expression
这与{FOO; BAR}
相同,只是一个块(括号中)没有类型。
答案 1 :(得分:1)
如果断言触发,则不会评估任何内容,但两个表达式必须具有正确的返回类型,否则此宏将破坏编译。
答案 2 :(得分:1)
基本想法非常简单。他试图得到一个效果,就像他写的那样:if (!expr) debugbreak();
。然而,对于宏,他希望将其作为单个表达式。为此,他使用||
来评估它的左参数,然后当且仅当它为假时,计算正确的参数 - 然后产生一个整体结果,即两个操作数的逻辑或。
在这种情况下,他并不真正关心关于作为结果产生的逻辑OR;他只想要评价左边,然后如果是假的评价右边。编译器,但 非常关心 - 特别是,它要求||
的两个操作数都有一些可以转换为bool(或者,在C,0或1中)的类型。 / p>
为了给编译器,他使用逗号运算符来计算其左操作数,然后使用右操作数并生成右操作数的值作为结果。这让他得到了debugbreak()
的评估,而0
通过给它一个int作为结果值来保持编译器的快乐,然后它可以与expr
产生的任何值进行OR运算。产生整体表达的结果(当然,这是无关紧要的,几乎肯定会被忽略)。
答案 3 :(得分:0)
我认为你所有人都缺少的是(A || B)遵循短路规则的事实。
如果A为真,则无需评估B.因为不需要评估B,所以DebugBreak()永远不会被调用。
如果A为假,那么我们必须评估B以确定(A || B)的输出。没有短路。 (DebugBreak(),0)更合适(DebugBreak(),false)
http://www.student.cs.uwaterloo.ca/~cs132/Weekly/W02/SCBooleans.html
http://msdn.microsoft.com/en-us/library/zs06xbxh(VS.80).aspx