0

Why does this code print 10 = -246 instead of 10 = 10? Does the pointer size matter?

#include <stdio.h>

int main() {
    int i = 10;
    int j = -1;

    char *p, *q;

    p = (char*) &i;
    q = (char*) &j;

    *q = *p;

    printf("%d = %d\n", i, j);

    return 0;
}
Ron
  • 14,674
  • 4
  • 34
  • 47
user9515151
  • 313
  • 1
  • 3
  • 6
  • The `int` is made up of several bytes (`char` is one byte) ... if you want to copy the value then you need to copy all of the bytes, not just 1 – M.M Mar 19 '18 at 08:38

5 Answers5

1

First of all, the result here depends on CPU endianess. You appear to have a little endian CPU.

Assuming int is 32 bit 2's complement, -1 is stored in 4 bytes as 0xFFFFFFFF. A char access only affects one byte. Since you have little endian, it will be the least significant byte in your case. This byte will get overwritten with the value 10, 0x0A. You end up with 0xFFFFFF0A which is the 2's complement representation of -246.


Please note that the char type has implementation-defined signedness and should therefore always be avoided when doing bit/byte manipulations. Use uint8_t instead.

Also note that accessing one data type through a pointer of a different type is risky and poorly-defined, in all other cases than when using character types specifically (uint8_t is a character type), because they are an exception to the "strict aliasing rule".

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • `uint8_t` may or may not be a character type, unfortunately. There could be an extended integer type defined with 8 bit size ([reference](https://stackoverflow.com/a/12666311/1505939)) – M.M Mar 19 '18 at 09:07
  • @M.M Nah that doesn't make sense in the real world. If `uint8_t` exists, then so does 8 bit `char`. It would then be utterly stupid of the compiler implementation to map `uint8_t` to anything but `unsigned char`. And even if it was possible to map it to some extended non-standard type, such a compiler would become useless and die out, since nobody wants to use a useless compiler. – Lundin Mar 19 '18 at 09:19
1

Does the pointer size matter?

No, the size of the pointer doesn't matter. What matter is the type of pointer, i.e. the type it points to.

The number of bytes copied when assigning through a pointer depends on the pointer type. If the pointer type is a char pointer, it will copy sizeof(char) bytes. If the pointer type is an int pointer, it will copy sizeof(int) bytes.

Why does this code print 10 = -246 instead of 10 = 10?

It's system dependent. Since you get this result, you are probably on a little endian system which means that data in memory is stored with LSB first (i.e. a pointer to a variable points to LSB of that variable).

So what happens in your code is that LSB of variable i is copied to LSB of variable j. Since sizeof(int) is more than 1, you'll not end in a situation where i and j are equal. Simply because you didn't copy all bytes of i into j.

Assuming a 32 bit int it may look like:

enter image description here

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
0

Assume the CPU is 32bit.

First question: why print 10 = -246

i = 10;  (0x0000 000A)
j = -1;  (0xFFFF FFFF) Two's Complement

*q pointer to the lowest 8bit of integer j, after *q = 10;, j becomes 0xFFFF FF0A which is the Two's Complement of -246

refer How Computers Represent Negative Binary Numbers?

Second question: does the pointer size matter?

Yes, covert int pointer to char pointer will lose the 24bit data in this case.

Larry.He
  • 604
  • 5
  • 16
0

Here p & q is a char pointer. p = (char*) &i; So p will point to the first byte of the integer var i which is of 4 bytes. So on dereferncing p you will get 10(00001010).

q = (char*) &j; As j = -1, it is the largest negative no. It means j var will have all 1's in 32 bits(11111111 11111111 11111111 11111111)

*q = *p; In this line you are copying the lowest first byte(00001010) from i's location to j's location first byte because both pointers are of char *. So now after copying, value in j's location will be: 11111111 11111111 11111111 00001010 which is equivalent to -246. Calculate the 2's complement of 11111111 11111111 11111111 00001010. It will give you -246.

Ravi
  • 140
  • 6
  • I tried to add this loop and it solved the problem but i don't know if it's a best way to do it; for(int k = 1; k <= 3; k++) q[k] = (char)NULL; – user9515151 Mar 19 '18 at 09:32
  • Before going for the solution, first of all what you want to achieve in this program? for(int k = 1; k <= 3; k++) q[k] = (char)NULL; This line is ideally setting last 3 bytes to NULL i.e. Zero. Instead you can initialize the j var with zero. – Ravi Mar 19 '18 at 09:41
  • The exercise here is printing 10 = 10 without assigning new numbers directly to the int variables but working only in char pointers – user9515151 Mar 19 '18 at 09:54
  • Better you ca use memset after printf statement to zeroed the next 3 bytes. memset(q+1, 0, 3); – Ravi Mar 19 '18 at 10:36
0

You have to do a casting like this to have the value of i in j: * (int*)p = * (int*)q It will convert the type of your pointer and you are going to “transfer” the value of i in j.

Or in addition you can do it without casting using a for loop loke this: `

for(int k=0; k<sizeof(int);k++){
    *(p+k) = *(q+k);
}

` With this loop you are going to write every single bit of i in every byte of k one byte at time. This because int have a 4 byte structure and char have a 1 byte structure.

Anhilator
  • 1
  • 1