Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Short-circuiting on boolean operands without side effects

For the bounty: How can this behavior can be disabled on a case-by-case basis without disabling or lowering the optimization level?

The following conditional expression was compiled on MinGW GCC 3.4.5, where a is a of type signed long, and m is of type unsigned long.

if (!a && m > 0x002 && m < 0x111)

The CFLAGS used were -g -O2. Here is the corresponding assembly GCC output (dumped with objdump)

120:    8b 5d d0                mov    ebx,DWORD PTR [ebp-0x30]
123:    85 db                   test   ebx,ebx
125:    0f 94 c0                sete   al
128:    31 d2                   xor    edx,edx
12a:    83 7d d4 02             cmp    DWORD PTR [ebp-0x2c],0x2
12e:    0f 97 c2                seta   dl
131:    85 c2                   test   edx,eax
133:    0f 84 1e 01 00 00       je     257 <_MyFunction+0x227>
139:    81 7d d4 10 01 00 00    cmp    DWORD PTR [ebp-0x2c],0x110
140:    0f 87 11 01 00 00       ja     257 <_MyFunction+0x227>

120-131 can easily be traced as first evaluating !a, followed by the evaluation of m > 0x002. The first jump conditional does not occur until 133. By this time, two expressions have been evaluated, regardless of the outcome of the first expression: !a. If a was equal to zero, the expression can (and should) be concluded immediately, which is not done here.

How does this relate to the the C standard, which requires Boolean operators to short-circuit as soon as the outcome can be determined?

like image 263
Unsigned Avatar asked Sep 08 '11 22:09

Unsigned


2 Answers

The C standard only specifies the behavior of an "abstract machine"; it does not specify the generation of assembly. As long as the observable behavior of a program matches that on the abstract machine, the implementation can use whatever physical mechanism it likes for implementing the language constructs. The relevant section in the standard (C99) is 5.1.2.3 Program execution.

like image 144
R.. GitHub STOP HELPING ICE Avatar answered Oct 01 '22 18:10

R.. GitHub STOP HELPING ICE


It is probably a compiler optimization since comparing integral types has no side effects. You could try compiling without optimizations or using a function that has side effects instead of the comparison operator and see if it still does this.

For example, try

if (printf("a") || printf("b")) {
    printf("c\n");
}

and it should print ac

like image 22
David Brown Avatar answered Oct 01 '22 16:10

David Brown