Weird output when trying to print static variable from function in printf statement

Viewed 134

I tried print the value of static variable 5 times by declaring it in a function where its increments itself for each call and then adding it to global variable and return its value in a printf statement but the output was different than usual all value of the static variable incremented first and output was in the reverse order after adding to the global variable(All the value was printed using a single printf statement)

#include <stdio.h>

int global_variable = 10;

int fun(){
    static int var;
    printf("The value of var is %d\n", var);
    var++;
    return global_variable + var;
}

int main()
{
    //This works fine
    printf("%d\n", fun());
    printf("%d\n", fun());
    printf("%d\n", fun());
    printf("%d\n", fun());
    printf("%d\n", fun());

    //This works weird this prints value in reverse order not like the former case
    printf("\n%d\n%d\n%d\n%d\n%d\n",fun(), fun(), fun(), fun(), fun());

    return 0;
}

output of first one:

The value of var is 0
11
The value of var is 1
12
The value of var is 2
13
The value of var is 3
14
The value of var is 4
15

output of second one:

The value of var is 5
The value of var is 6
The value of var is 7
The value of var is 8
The value of var is 9

20
19
18
17
16

In two set of code first one works fine but the second is what i don't understand. Please explain.

2 Answers

The order of evaluation of the parameters to a function is unspecified. That means they may be evaluated in any order.

Section 6.5.2.2p10 of the C standard regarding function calls states:

There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

In a case like this, it's proper not to call func more than once in a given expression, or more accurately not more than once without an intervening sequence point.

cppreference.com says of evaluation order that:

Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified

In this, function call arguments are different from the comma operator, which is one of the exceptions that has a defined order. In all of left, right, left || right, left && right and left ? right1 : right2, the left expression is evaluated before the right one.

As it happens, when I tested that with Clang, it evaluated the fun() calls in exactly the opposite order to GCC. Which only goes to show that you can't count on it in practice.

The right-to-left evaluation may have basis on how function call arguments are/were passed on the stack. Because C supports variable numbers of arguments, they're passed with the rightmost ones first, i.e. so that the leftmost ones are always at the same position relative to the stack at function entry. Of course, for ABIs that pass arguments in registers, the order isn't that clear.

(Note, I'm not sure how e.g. the x86-64 ABI passes variable args, like to printf() here. I'm just suggesting a possible historical connection.)

Related