问题
Recently, I've come across a piece of code like this (not the real one, but a shorter example based upon it):
#include <stdio.h>
int main()
{
int n;
printf ("n? ");
scanf ("%d", &n);
n%2 && printf ("N is odd\n"); /* <-- this is it */
return 0;
}
In case anybody didn't get it, this code is the equivalent of:
int main()
{
int n;
printf ("n? ");
scanf ("%d", &n);
if (n%2)
printf ("N is odd\n");
return 0;
}
A disassembly of this code compiled with GCC 4.4.5-8 for x86-64 bits gives this for the part in which n
is evaluated and printf()
is conditionally called:
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
Sounds like the code an if
statement would generate. The "standard" way gives this:
andl $1, %eax
testb %al, %al
je .L2
movl $.LC2, %edi
call puts
.L2:
movl $0, %eax
leave
ret
Slighly shorter, and a bit faster too, because the compiler can use puts()
instead of printf()
, as it has detected that printf()
is being used to print a single string, and its return value is not used. The former example must evaluate the second expression after &&
because the first one evaluated to true, so printf()
had to be used to get a value to evaluate with.
So my point is: Could this shortcut evaluation trick be considered good coding? It works but... does it any better other than helping to win one-liner C contests? Judging by the example I've provided I'd say no, but may it exist an example that proves otherwise?
NOTE: while trying to compile the original code, the compiler even generated an ICE (MingW 2.95.2) with a text error saying something about "error while executing do_jump" or something like that.
回答1:
This technique is not useful in general as it is contrary to generally-accepted convention and leads to unreadable code. (Note that this technique is acceptable in other languages, such as perl, where it is a commonly-used idiom.)
One place you may be forced to use this technique is in a function-like macro.
#define foo(x, y) (((x) % 2) && (y))
You cannot write the macro as
#define foo(x, y) if ((x) % 2) (y)
Because that would mess up things like
if (a) foo(x, y); else bar();
The usual workaround of
#define foo(x, y) do { if ((x) % 2) (y); } while (0)
does not work with the comma operator.
for (i = 0, foo(x, y); i < 10; i++) ...
That said, any such use of this idiom should be well-commented.
来源:https://stackoverflow.com/questions/20930483/shortcut-evaluation-instead-of-doing-ifcondition-expression