mcl*_*fix 0 c lazy-evaluation short-circuiting
最近,我遇到了一段这样的代码(不是真正的代码,而是一个基于它的简短示例):
#include <stdio.h>
int main()
{
int n;
printf ("n? ");
scanf ("%d", &n);
n%2 && printf ("N is odd\n"); /* <-- this is it */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果有人没有得到它,这段代码相当于:
int main()
{
int n;
printf ("n? ");
scanf ("%d", &n);
if (n%2)
printf ("N is odd\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于x86-64位,使用GCC 4.4.5-8编译的此代码的反汇编为此部分提供了n评估并printf()有条件地调用的部分:
andl $1, %eax
testb %al, %al
je .L3
movl $.LC2, %eax
movq %rax, %rdi
movl $0, %eax
call printf
testl %eax, %eax
.L3:
movl $0, %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
听起来像if语句会生成的代码."标准"方式给出了这样的:
andl $1, %eax
testb %al, %al
je .L2
movl $.LC2, %edi
call puts
.L2:
movl $0, %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
因为编译器可以使用puts()而不是printf(),因为它已经检测到printf()用于打印单个字符串,并且不使用其返回值,所以可以使用更短,更快一点.之前的示例必须在之后评估第二个表达式,&&因为第一个表达式的计算结果为true,因此printf()必须使用它来获取要评估的值.
所以我的观点是:这种快捷方式评估技巧可以被视为良好的编码吗?它有效,但除了帮助赢得单线C比赛之外,它还能做得更好吗?从我提供的例子来看,我会说不,但可能存在一个证明不然的例子吗?
注意:在尝试编译原始代码时,编译器甚至生成了一个ICE(MingW 2.95.2),文本错误说明了"执行do_jump时出错"或类似的内容.
这种技术一般没用,因为它与普遍接受的惯例相反并导致不可读的代码.(请注意,这种技术在其他语言中是可以接受的,例如perl,它是一种常用的习惯用法.)
您可能被迫使用此技术的一个地方是类似函数的宏.
#define foo(x, y) (((x) % 2) && (y))
Run Code Online (Sandbox Code Playgroud)
你不能把宏写成
#define foo(x, y) if ((x) % 2) (y)
Run Code Online (Sandbox Code Playgroud)
因为那会弄乱像
if (a) foo(x, y); else bar();
Run Code Online (Sandbox Code Playgroud)
通常的解决方法
#define foo(x, y) do { if ((x) % 2) (y); } while (0)
Run Code Online (Sandbox Code Playgroud)
不适用于逗号运算符.
for (i = 0, foo(x, y); i < 10; i++) ...
Run Code Online (Sandbox Code Playgroud)
也就是说,任何对这种习语的使用都应该得到很好的评价.