Home > Back-end >  Can someone please explain the output of this C program?
Can someone please explain the output of this C program?

Time:07-21

Here is the code:

int a=256;
char *x= (char *)&a;
*x   = 1;
*x =x[0]  ;
printf("a=%d\n", a);

The output is:

a=257

CodePudding user response:

int a=256;

Initialized integer variable with value 256. On little-endian machine memory layout is:

00 01 00 00 ...

char *x= (char *)&a;

x is pointer to least significant byte of a (on little endian machine).

00 01 00 00 ...
 ^ -- x points here

*x = 1;

Set byte where x points to 1, then move x to next byte. Memory is:

01 01 00 00 ...
    ^-- x points here

*x =x[0] ;

Unspecified behaviour, *x and x[0] are equal (x[0] is *(x 0)) . Post-increment is ignored in your implementation.

UPD: actually it is not ignored but overwritten by assignment. x[0] increases second byte:

01 02 00 00
    ^ -- x

and then value taken before increment (01) placed to the same place by *x=

01 01 00 00

CodePudding user response:

I'm going to take the posted code one line at a time.

int a=256;

I presume this is straightforward enough.

char *x= (char *)&a;

This sets a char pointer to point to just one byte of the multi-byte int value. This is a low-level, machine-dependent, and not necessarily meaningful operation. (Also x is a poor, unidiomatic name for a pointer variable.)

*x   = 1;

This both sets the byte pointed to by x, and increments x to point to the next byte. In general that's a sensible operation — for example, it's how we often fill characters into a text buffer one at a time. In this context, though, it's borderline meaningless, because it's rare to move along the bytes of an int variable one at a time, setting or altering them.

*x =x[0]  ;

And then this line is the kicker. I can't explain what it does, in fact no one can explain what it does, because it's undefined. More on this below.

printf("a=%d\n", a);

Obviously this prints the value of a, although after what poor a has been through, it's hard to say what kind of bloody mess might be left of its bits and bytes.


And now let's take a second look at that line

*x =x[0]  ;

One thing we can say is that by the rules of pointer arithmetic, the subexpressions *x and x[0] are identical, they do exactly the same thing, they access the value pointed to by x. So whatever value is pointed to by x, this expression tries to modify it twice: once when it says x[0] , and then a second time when it says *x = … to assign something to *x. And when you have one expression that tries to modify the same thing twice, that's poison: it leads to undefined behavior, and once you're in undefined behavior territory, you can't say — no one can say — what your program does.

In fact, I tried your code under two different compilers, and I got two different answers! Under one compiler the code printed 257, as yours did, but under the other compiler it printed 513. How can that be? What's the right answer? Well, in the case of undefined behavior, since there is no one right answer, it's not wrong — in fact it's more or less expected — for different compilers to give different results.

You can read much more about undefined behavior, and undefined expressions like this one, at the canonical SO question on this topic, Why are these constructs using pre and post-increment undefined behavior? Your expression is equivalent to the classic one i = i which is specifically discussed in several of the answers to that other question.

  • Related