Raulp
Raulp

Reputation: 8146

Output Explanation of this program in C?

I have this program in C:

int main(int argc, char *argv[])
{

  int i=300;
  char *ptr = &i;
  *++ptr=2;
  printf("%d",i);
  return 0;
}

The output is 556 on little endian.

I tried to understand the output. Here is my explanation.

Question is Will the answer remains the same in the big endian machine?

i = 300; => i = 100101100 //in binary in word format => B B Hb 0001 00101100 where B = Byte and Hb = Half Byte

(A)=> in memory (assuming it is Little endian))

0x12345678 - 1100 - 0010 ( Is this correct for little endian)

0x12345679 - 0001 - 0000

0x1234567a - 0000 - 0000

0x1234567b - 0000 - 0000

0x1234567c - Location of next intezer(location of ptr++ or ptr + 1 where ptr is an intezer pointer as ptr is of type int => on doing ++ptr it will increment by 4 byte(size of int))

when

(B)we do char *ptr = &i; ptr will become of type char => on doing ++ptr it will increment by 1 byte(size of char) so on doing ++ptr it will jump to location -> 0x12345679 (which has 0001 - 0000) now we are doing ++ptr = 2 => 0x12345679 will be overwritten by 2 => 0x12345679 will have 00*10** - 0000 instead of 000*1* - 0000

so the new memory content will look like this :

(C)

0x12345678 - 1100 - 0010

0x12345679 - 0010 - 0000

0x1234567a - 0000 - 0000

0x1234567b - 0000 - 0000

which is equivalent to => B B Hb 0010 00101100 where B = Byte and Hb = Half Byte

Is my reasoning correct?Is there any other short method for this? Rgds, Softy

Upvotes: 5

Views: 1109

Answers (4)

cHao
cHao

Reputation: 86505

In a little-endian 32-bit system, the int 300 (0x012c) is typically(*) stored as 4 sequential bytes, lowest first: 2C 01 00 00. When you increment the char pointer that was formerly the int pointer &i, you're pointing at the second byte of that sequence, and setting it to 2 makes the sequence 2C 02 00 00 -- which, when turned back into an int, is 0x22c or 556.

(As for your understanding of the bit sequence...it seems a bit off. Endianness affects byte order in memory, as the byte is the smallest addressable unit. The bits within the byte don't get reversed; the low-order byte will be 2C (00101100) whether the system is little-endian or big-endian. (Even if the system did reverse the bits of a byte, it'd reverse them again to present them to you as a number, so you wouldn't notice a difference.) The big difference is where that byte appears in the sequence. The only places where bit order matters, is in hardware and drivers and such where you can receive less than a byte at a time.)

In a big-endian system, the int is typically(*) represented by the byte sequence 00 00 01 2C (differing from the little-endian representation solely in the byte order -- highest byte comes first). You're still modifying the second byte of the sequence, though...making 00 02 01 2C, which as an int is 0x02012c or 131372.

(*) Lots of things come into play here, including two's complement (which almost all systems use these days...but C doesn't require it), the value of sizeof(int), alignment/padding, and whether the system is truly big- or little-endian or a half-assed implementation of it. This is a big part of why mucking around with the bytes of a bigger type so often leads to undefined or implementation-specific behavior.

Upvotes: 7

Viktor Latypov
Viktor Latypov

Reputation: 14467

I like experiments and that's the reason for having the PowerPC G5.

stacktest.c:

int main(int argc, char *argv[])
{
  int i=300;
  char *ptr = &i;
  *++ptr=2;
  /* Added the Hex dump */
  printf("%d or %x\n",i, i);
  return 0;
}

Build command:

powerpc-apple-darwin9-gcc-4.2.1 -o stacktest stacktest.c

Output:

131372 or 2012c

Resume: the cHao's answer is complete and in case you're in doubt here is the experimental evidence.

Upvotes: 1

gliderkite
gliderkite

Reputation: 8928

This is your int:

int i = 300;     

And this is what the memory contains at &i: 2c 01 00 00 With the next instruction you assign the address of i to ptr, and then you move to the next byte with ++ptr and change its value to 2:

char *ptr = &i;
*++ptr = 2;

So now the memory contains: 2c 02 00 00 (i.e. 556). The difference is that in a big-endian system in the address of i you would have seen 00 00 01 2C, and after the change: 00 02 01 2C.

Even if the internal rappresentation of an int is implementation-defined:

For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; signed char shall not have any padding bits. There shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M ≤ N). If the sign bit is zero, it shall not affect the resulting value. If the sign bit is one, the value shall be modified in one of the following ways: — the corresponding value with sign bit 0 is negated (sign and magnitude); — the sign bit has the value −(2M) (two’s complement); — the sign bit has the value −(2M − 1) (ones’ complement). Which of these applies is implementation-defined, as is whether the value with sign bit 1 and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones’ complement), is a trap representation or a normal value. In the case of sign and magnitude and ones’ complement, if this representation is a normal value it is called a negative zero.

Upvotes: 3

harald
harald

Reputation: 6126

This is implementation defined. The internal representation of an int is not known according to the standard, so what you're doing is not portable. See section 6.2.6.2 in the C standard.

However, as most implementations use two's complement representation of signed ints, the endianness will affect the result as described in cHaos answer.

Upvotes: 3

Related Questions