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

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时出错"或类似的内容.

Ray*_*hen 5

这种技术一般没用,因为它与普遍接受的惯例相反并导致不可读的代码.(请注意,这种技术在其他语言中是可以接受的,例如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)

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