2

This is a sample code just to show a different output from the LLVM compiler and the GCC. I wonder why? The answer should be very simple, but I can't see it. (Xcode 4.6.1)

The code:

#include <stdio.h>

#define MAX(a,b) ( (a) > (b) ? (a) : (b) )

int increment() {
    static int i = 42;
    i += 5;
    printf("increment returns %d\n",i);
    return i;
}

int main( int argc, char ** argv ) {
    int x = 50;
    printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));
    printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));
    return 0;
}

The LLVM Output:

increment returns 47
increment returns 52
increment returns 57
max of 50 and 47 is 57
increment returns 62
increment returns 67
increment returns 72
max of 50 and 62 is 72

GCC Output:

increment returns 47
increment returns 52
max of 50 and 52 is 50
increment returns 57
increment returns 62
increment returns 67
max of 50 and 67 is 62
zago
  • 532
  • 2
  • 10

2 Answers2

13

The order of evaluation of the parameters is not defined specified. So this:

printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));

causes undefined unspecified behavior . That's why you have different results on both compilers.

Another (potential) problem is: MAX - it could cause two calls to increment. Avoid using such macros.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
  • 1
    See http://stackoverflow.com/questions/376278/parameter-evaluation-order-before-a-function-calling-in-c for more, and especially the excellent link there. – Rob Napier Apr 10 '13 at 15:15
  • 1
    And also required reading for all C programmers: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html – Rob Napier Apr 10 '13 at 15:16
  • @DavidGrayson, because 47 is less than 50, so the false branch of the ternary expression is not executed. – SK-logic Apr 10 '13 at 15:55
  • 6
    No. That's not undefined behaviour. It's *unspecified behaviour*. There are sequence points when increment is called, when increment returns, and in the ternary operator. – autistic Apr 10 '13 at 15:56
  • @modifiablelvalue - right, thanks. I still have troubles making difference between _unspecified_ and _undefined_ behavior. – Kiril Kirov Apr 10 '13 at 16:50
  • 3
    @KirilKirov Good answer. The standard imposes no requirements of undefined behaviour. As implied by the unison of the two words, "undefined behaviour" does in fact mean *anything could happen*. Unspecified behaviour implies that one of two or more possible behaviours are used. In this case, it seems like there are eight (or more) orders that the expressions could be evaluated in. Implementation-defined behaviour is unspecified behaviour which the implementation is required to document. – autistic Apr 10 '13 at 17:04
-2

The LLVM code produces the right results according to ANSI C. If you don't want increment to be called more than once per print statement, save the return value in a variable and use that. Mentally stepping through the code, the display should be increment returns 47 increment returns 52 increment returns 57 max of 50 and 47 is 57 increment returns 62 increment returns 67 max of 50 and 62 is 72 So my initial reaction and study of the code was wrong, and the LLVM output is right. The reason for the LLVM result is that increment is called three times for each print statement in main. The way to make this code print sensible output is to save the value returned by increment in a variable and print the variable, not another call to increment. The difference in results doesn't depend on undefined behavior as far as I know, but on correct versus incorrect conformance to ANSI C.

John
  • 1
  • 3