快捷方式评估而不是if(条件)表达;

时间:2014-01-05 05:33:46

标签: 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;
}

如果有人没有得到它,这段代码相当于:

int main()
{
  int n;

  printf ("n? ");  
  scanf ("%d", &n);

  if (n%2) 
    printf ("N is odd\n");

  return 0;
}

使用GCC 4.4.5-8针对x86-64位编译的此代码的反汇编为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

听起来像if语句会产生的代码。 “标准”方式给出了这个:

        andl    $1, %eax
        testb   %al, %al
        je      .L2
        movl    $.LC2, %edi
        call    puts
.L2:
        movl    $0, %eax
        leave
        ret

更短,也更快一点,因为编译器可以使用puts()代替printf(),因为它已检测到printf()正用于打印单个字符串,并且它的返回值没有使用。前一个示例必须在&&之后评估第二个表达式,因为第一个表达式被评估为true,因此必须使用printf()来获取要评估的值。

所以我的观点是:这种快捷方式评估技巧可以被认为是良好的编码吗?它有效,但除了帮助赢得单线C比赛之外,它还能做得更好吗?从我提供的例子来看,我会说不,但可能存在一个证明不然的例子吗?

注意:在尝试编译原始代码时,编译器甚至生成了一个ICE(MingW 2.95.2),文本错误说明了“执行do_jump时的错误”或类似内容。

1 个答案:

答案 0 :(得分:5)

这种技术一般没用,因为它与普遍接受的惯例相反,导致代码不可读。 (请注意,这种技术在其他语言中是可以接受的,例如perl,它是一种常用的习语。)

您可能被迫使用此技术的一个地方是类似函数的宏。

#define foo(x, y) (((x) % 2) && (y))

您无法将宏编写为

#define foo(x, y) if ((x) % 2) (y)

因为这会弄乱像

这样的东西
if (a) foo(x, y); else bar();

的常用解决方法
#define foo(x, y) do { if ((x) % 2) (y); } while (0)

不适用于逗号运算符。

for (i = 0, foo(x, y); i < 10; i++) ...

也就是说,任何对这种习语的使用都应该得到很好的评论。