4

Here I have a function named max(a,b) to get the max number out of two. And I found that the value of variable a and b using printf() are different after executing

printf("maxab()=%d after max: a=%d b=%d \n",max(a++,b++),a,b);

when a and b are Global variables and Local variables. Below is my code:

#include<stdio.h>

int max(int a,int b)
{

    if(a>b)
    {
        //printf("In func max():%d %d \n",a,b);
        return a;
    }
    else {
        //printf("In func max():%d %d \n",a,b);
        return b;
    }

}
void jubu_test(void)
{
    int a=1;
    int b=2;    
    printf("maxab()=%d after max: a=%d b=%d \n",max(a++,b++),a,b);  //a=2,b=3
}
int c=2;
int d=1;
void quanju_test(void)
{
    printf("maxcd()=%d  c=%d d=%d \n",max(c++,d++),c,d);    //c=2,d=1
    c=2;
    d=1;
    int f=max(c++,d++);
    printf("maxcd()=%d after max: c=%d d=%d \n",f,c,d);     //c=3,d=2
}   
int main(int argc, char** argv)
{
    jubu_test();
    quanju_test();
}

The result I get on my computer is:

maxab()=2 after max: a=2 b=3
maxcd()=2  c=2 d=1
maxcd()=2 after max: c=3 d=2

My question is: Why in the second output a and b is their original value and why the third output is a+1 and b+1? Why when a and b are Global variables, the value of a and b printed out only changes when we execute max(a++,b++) first? Why when a and b are local variables it doesn't matter?

Thanks! (using gcc 5.3.0 on windows 10)

11
  • see stackoverflow.com/questions/949433/… Commented Mar 30, 2017 at 7:07
  • 1
    @SouravGhosh Actually, I'm trying to find it out. After I proposed the duplicate I start thinking deeply on it. In this case incremented variables are different, so not the case like i++ + ++i BTW gcc shows a lot of warnings on sequence point on inc in function call Commented Mar 30, 2017 at 7:19
  • 1
    @SouravGhosh I retracted it. BTW warnings are clear...if gcc is evaluating them correctly Commented Mar 30, 2017 at 7:28
  • 1
    Actually, this is UB and not just unspecified. Commented Mar 30, 2017 at 7:48
  • 1
    add -Wall -Wextra and -pedantic-errors and you'll see them. -Wall it is enough for your specific case. Commented Mar 30, 2017 at 8:01

2 Answers 2

5

The expression printf(... max(a++,b++),a,b); is undefined behavior as per Why are these constructs (using ++) undefined behavior?.

The evaluation of a++ is not sequenced in relation to the evaluation of a, same for b++ and b. It doesn't matter that there is a sequence point before the function is called, because the sub-expressions may be evaluated before that, in any order.

Undefined behavior = always a bug. Means that the program could have any kind of behavior, print anything, crash & burn etc.

The reason why it is undefined behavior is this, C11 6.5/2:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

(a is a scalar object - not an array or struct etc. a++ causes a side-effect of updating the variable. This is unsequenced in relation of the value computation of a elsewhere in the same expression.)


Not to be confused with unspecified behavior, which means that the program will behave deterministically but you can't know in which way. For example, the order of evaluation of function arguments is unspecified behavior:

int func (void)
{
  static int x=0;
  x++;
  return x;
}

printf("%d %d", func(), func());

This may print either 1 2 or 2 1 and we can't know or assume which applies. The compiler does not need to document this, nor does it have to behave consistently throughout the program. It could pick one order in one case and another order in another case.

Code relying on unspecified behavior is bad, but won't behave completely erratically like code containing undefined behavior.

Sign up to request clarification or add additional context in comments.

1 Comment

It's indeed possible for order to be a++ -> a -> call max(), which makes my earlier comment about sequence point a nonsense. In the end it always comes to undefined behaviour. +1
3

As I believe, it has nothing to do with the scope of the variables. C does not specify the exact order of the evaluation of function arguments. So, this is unspecified behaviour.

5 Comments

This is true but it's still weird that it behaves differently in either case. What is the underlying reasoning (even if it isn't consistent amongst various C implementations)?
@jakeehoffmann You would have to look assembly (which we don't have) to know for sure. But that seems pointless exercise since code is broken to begin with.
@jakeehoffmann - The reason is the compilers static analysis of the code, where it concluded (possibly randomly) to evaluate the arguments in a different order every time. It's within its right, and why one should not depend on behavior that is unspecified (because unspecified, unlike implementation defined, means it doesn't have to be documented).
@jakeehoffmann The underlying reason is to give compilers the freedom to evaluate their internal expression trees in any order they like, so that the generated code will be slightly faster.
This max(a++,b++),a,b is also undefined behavior, because there is a side effect on updating a which is not sequenced in relation to a in the same expression, and the a is not used to determine which value to store.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.