1

Prefix Increment operator not sending incremented value of the variable (x) in a call to printf(), when compiled with GCC.

Here is my code;

#include <stdio.h>

int bitcount(unsigned);

int main()
{
    unsigned int x = 127;

    printf("bitcount[%d] : %d\n", x, bitcount(x));
    printf("bitcount[%d] : %d\n", ++x, bitcount(x));

    return 0;
}

int bitcount(unsigned int x)
{
    int bitcount = 0;
    for(; x != 0; x >>= 1)
        if( x & 1 )
            bitcount++;

    return bitcount;
}

in main() method, the problem is at the line below;

printf("bitcount[%d] : %d\n", ++x, bitcount(x));

X should be incremented and send to the bitcount() with the incremented value of x. The value of x is incremented however, instead of incremented value, the old value is send to the bitcount() function.

I've tried the same thing with MS VS, this misbehaving didn't occur. The outputs are as below;

Output of Program compiled with GCC on Windows 10

D:\C\chapter2>gcc bitcount.c -o bitcount.exe

D:\C\chapter2>bitcount
bitcount[127] : 7
bitcount[128] : 7

Output of Program compiled with MS VS on Windows 10

bitcount[127] : 7
bitcount[128] : 1

To ensure the problem, I've updated code to see the value which is sent to the function;

Bitcount V2

#include <stdio.h>

int bitcount(unsigned);

int main()
{
    unsigned int x = 127;

    printf("bitcount[%d] : %d\n", x, bitcount(x));
    printf("bitcount[%d] : %d\n", ++x, bitcount(x));

    return 0;
}

int bitcount(unsigned int x)
{
    printf("\nDebug::\tbitcount()::x=%d\n", x);
    int bitcount = 0;
    for(; x != 0; x >>= 1)
        if( x & 1 )
            bitcount++;

    return bitcount;
}

Output of Bitcount v2 compiled with GCC on Windows 10 system

Debug:: bitcount()::x=127 bitcount[127] : 7

Debug:: bitcount()::x=127 bitcount[128] : 7

As it is obvious, GCC sending the old value of X to bitcount() function.

To generalize the problem, I've written the program below;

InsideFunc.c

#include <stdio.h>

int func(unsigned);

int main()
{
    unsigned int x = 127;

    printf("x: %d, func(): %d\n",   x, func(x));
    printf("x: %d, func(): %d\n", ++x, func(x));

    return 0;
}

int func(unsigned x)
{
    printf("\n\tDebug::func()::x=%d\n", x);

    return x;
}

Output compiled with GCC on Windows 10 System

D:\C\chapter2>gcc InsideFunc.c -o InsideFunc.exe

D:\C\chapter2>InsideFunc

    Debug::func()::x=127

x: 127, func(): 127

    Debug::func()::x=127

x: 128, func(): 127

Again, value of the variable incremented but old value send to the function.

Here is my gcc version;

D:\C\chapter2>gcc --version
gcc (GCC) 5.2.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Any ideas ?

Late Note : I've just seen on The C Programming Language book of Kernighan & Ritchie, page 49 that which explains the order of evaluation in the function arguments are uncertain and compiler dependent;

Similarly, the order in which function arguments are evaluated is not specified, so the statement

printf("%d %d\n", ++n, power(2, n)); /*WRONG */

can produce different results with different compilers, depending on whether n is incremented before power is called. The solution, of course, is to write

++n;

printf("%d %d\n", n, power(2, n));

Levent Divilioglu
  • 11,198
  • 5
  • 59
  • 106
  • 4
    UB, as the function arguments evaluation and passing convention is not sequenced. – Sourav Ghosh Apr 21 '16 at 10:18
  • 3
    [Possible dupe](http://stackoverflow.com/q/949433/2173917) – Sourav Ghosh Apr 21 '16 at 10:19
  • I dont think this is a duplicate question. This problem occurs when passing the incremented value to the function. – Levent Divilioglu Apr 21 '16 at 10:21
  • 1
    `bitcount[%d]` --> `bitcount[%u]` – David Ranieri Apr 21 '16 at 10:23
  • @LeventDivilioglu It is a duplicate to the question Sourav linked. You use `x` twice in the same expression with no sequence point in between, and have an unsequenced side effect of `x`. Once that bug is fixed, there might also be the issue of order of evaluation of function parameters. – Lundin Apr 21 '16 at 13:35

2 Answers2

1

Order of evaluation of function calls arguments in is unspecified in C++, so on line:

printf("bitcount[%d] : %d\n", ++x, bitcount(x));

there is no guarantee that ++x will be evaluated before bitcount(x), so bitcount may be passed x pre-incrementation. All your compilers have different yet valid (i.e. standard-compliant) behavior.

mefyl
  • 264
  • 1
  • 6
  • 1
    Behavior is undefined. x is modified and read without a sequence point. – 2501 Apr 21 '16 at 10:26
  • It is true that the order of evaluation of arguments is unspecified. But there's more to this expression than that: `x` is used several times between sequence points, for other purposes than to determine which value to store in `x`. That is undefined behavior. So in this example you have both undefined and unspecified behavior. The former is always a severe bug, the latter could cause bugs if the program relies on the order. – Lundin Apr 21 '16 at 13:04
  • 1
    This is not a duplicate nor the issue is an undefined behavior. It is more related about how printf function is called and how the activation record is created before calling printf. When creating the activation record, the compiler starts pushing the printf variables from right to left; so, first the bitcount function is called before x is incremented and pushed into the stack, then x is incremented and pushed into the stack. – ssd Apr 21 '16 at 13:13
  • 1
    @merkez3110 No, that is simply not correct. See C99 6.5 "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored." And then also see 6.5.2.2/10 "The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified". – Lundin Apr 21 '16 at 13:29
  • 1
    I'll insist: Consider a foo function like `int foo(int x) {return (x * x);}`, just returning the square of x. When the `main()` code lines are `int x = 2; printf("x = %d foo(x) = %d\n", ++x, foo(x));` and you compile it simply via `gcc a.c -o a.exe` line, the code compiles & runs OK, spitting out `x = 3 foo(x) = 4`. However, when the same code is compiled via `gcc a.c -Wall -Werror -o a.exe` line, you'll get a warning like "operation on 'x' may be undefined." So, it's obvious that the undefined behavior is related to the order of the printf variables pushed into the stack. – ssd Apr 21 '16 at 13:45
1

Do not use incrementation inside expressions:

printf("bitcount[%d] : %d\n", x, bitcount(x));
x++;
printf("bitcount[%d] : %d\n", x, bitcount(x));
Aivars
  • 93
  • 7