0

I've gone through other similar questions, but trying to understand the situation I'm facing.

So, here's my two line C code.

int i=0;
printf("%d %d %d %d %d",i++,i--,++i,--i,i);

And here are the outputs I get from GCC and Turbo C Compiler.

GCC

Output:

-1 0 0 0 0

Turbo C

Output:

-1 0 0 -1 0

I tried all sorts of experiments with pre-increment operator individually, and both compilers work similar but when I use above printf statement, output differs.

I know that Turbo C is age-old compiler and now obsolete and non-standard but still can't get an idea what's wrong with above code.

Mat
  • 202,337
  • 40
  • 393
  • 406
Kushal
  • 3,112
  • 10
  • 50
  • 79
  • 4
    Your teacher should have explained that the behaviour is undefined - otherwise he/she is effectively wasting your time. The problem is that the compiler's free to decide when to apply the affects of the pre- and post-increments as long as they're between "sequence points". If you google that term, read the wikipedia article, you'll find the background information you need to understand the behaviour you describe. – Tony Delroy May 20 '11 at 05:15
  • 3
    http://c-faq.com/expr/seqpoints.html – Tony Delroy May 20 '11 at 05:26
  • @Tony: Thanks for the brief article over sequence points. – Kushal May 20 '11 at 05:28

4 Answers4

8

It's undefined behavior, you're both reading and modifying i multiple times without a sequence point. (The , in the function parameter list is not a sequence point, and the order of evaluation of function arguments is not defined either.)

The compiler can output whatever it wants in this situation. Don't do that.

Find a whole host of other similar issues by search this site for [C] undefined behavior. It's quite enlightening.

Community
  • 1
  • 1
Mat
  • 202,337
  • 40
  • 393
  • 406
1

Turbo C is evaluating the arguments for printf() from the last argument in the variable arguments list to the first, and printing in that order as well (i.e., it's filling in the last value, and then moving forward in the list with the last evaluation being the first variable argument in the list, which prints to the first integer-slot in your formatted-string). GCC on the other-hand is first is evaluating the arguments that have pre-fix operators, concatenating those results, and applying them to all pre-fix operators (i.e., it's applying --i and ++i which ends up equaling 0, and then using that value for both slots in the format string associated with those arguments). It's then moving to the post-fix operators (first i-- and then i++) , and finally it evaluates the variable args with no pre-fix or post-fix operators (i.e., the value of i, which at this point is simply 0). As others have noted, the ordering can be arbitrary.

Jason
  • 31,834
  • 7
  • 59
  • 78
0

There is a concrete explanation in case of Turbo C compiler for this case.

While GCC or other modern day compilers have an undefined behavior for such expressions where such ambiguity persists.

So, here's the explanation in the case of Turbo C compiler.

printf() has a right to left associativity while evaluating, but will print in its normal fashion of left to right.

Initially the value of i is initialized to 0,

starting with the rightmost i, it will be replaced by 0.

then, the second last --i, will be replaced by 0-1 = -1.

then the middle one ++i, will be replaced by -1+1 = 0.

then the second one i--, will be replaced by 0 but now the value of i becomes -1.

then the first one i++, will be replaced by -1 but now the value of i becomes 0.

And finally print in the left to right fashion as:

-1 0 0 -1 0

So, you can observe the usual behavior of Turbo C compiler on such expressions while there is no concrete rule of any other compiler on such expressions.

Himanshu Aggarwal
  • 1,803
  • 2
  • 24
  • 36
0

There is no guarantee of the order in which function parameters are evaluated; it's undefined behaviour.

This order could change from version to version or even compile to compile.

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
  • Strictly speaking, the order of evaluation is unspecified behavior, ie the compiler may implement this in one of many ways defined by the standard (left-to-right or right-to-left). The undefined behavior in the example is that "i" is modified several times inside the same expression, and that it is accessed for other purposes than to calculate the new value to be stored inside "i". – Lundin May 20 '11 at 06:44
  • @Mitch No, you said that the order of evaluation is undefined behavior, which is not true. – Lundin May 20 '11 at 09:41
  • @Lundin: the order in which [function] parameters are evaluated is undefined behaviour – Mitch Wheat May 20 '11 at 09:46
  • 1
    ISO 9899:1999 6.5.2.2.10 _The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is **unspecified**, but there is a sequence point before the actual call._ – Lundin May 20 '11 at 11:41
  • @Lundin: dude, that's what I'm saying! obviously not eloquently enough.... – Mitch Wheat May 20 '11 at 13:16
  • 1
    There are two problems here. Problem 1) the _undefined behavior_ that occurs when "i" is modified several times between sequence points, and accessed for other purposes than to determine the new value of "i". Problem 2) the _unspecified behavior_ of order of evaluation of function parameters. The accepted answer pointed out both of these as separate issues. Undefined behavior means that the program is allowed to go completely haywire and attack innocent bystanders. Unspecified behavior means that the program must behave according to one of several defined ways listed in the C standard. – Lundin May 20 '11 at 14:02
  • Point taken. FYI http://thesaurus.com/browse/unspecified – Mitch Wheat May 21 '11 at 01:42
  • by the way this code has an undefined behavior for the compilers other than Turbo C. but Turbo C gives a concrete behavior of solving this type of expressions. only modern day compilers have an undefined behavior for the expressions where ambiguity persists. – Himanshu Aggarwal Sep 21 '13 at 16:02