3

I have this piece of code that I saw it somewhere and I tried to figure out how it works, but I couldn't.

This is it :

#include <iostream>
using namespace std;

int main() {
   int a = 2;
   char * p = (char *) &a;
   *(p + 1) = 1;
   cout << (int *) p << endl;
   return 0;
}

I thought that in p it stores the binary of variable a like 00000010. Than in the next immediate address it stores 00000001. When I try to print (int *) p it takes 4 bytes from that address and converts it into int.

When I ran the program the result wasn't that expected. It shows only the address of variable a. No change observed.

Could you please explain me how this works and why ?

PS : If I want to show the value of p it shows only 2 not 258 how I expected.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
cristi.gherghina
  • 311
  • 1
  • 6
  • 18
  • 2
    this `*(p + 1) = 1;` is undefined behaviour. – 101010 Nov 13 '15 at 10:36
  • why the values of p does not change when converted to int ? Shouldn't it be 258 instead of just 2? – cristi.gherghina Nov 13 '15 at 10:40
  • Why it's not 2^8 + 2^1. That's what I want to know. – cristi.gherghina Nov 13 '15 at 10:42
  • It is only UB if you end up with some sort of garbage/trap representation. Apart from that, you can always split something up in characters/pointer to characters without breaking aliasing rules. It is however implementation-defined behavior, since the code relies both on signedness format and endianess. – Lundin Nov 13 '15 at 10:43
  • @Lundin: Why trap representation? I also thought you could access any object using char pointer – Giorgi Moniava Nov 13 '15 at 10:44
  • @Giorgi You can access every object with a char pointer, that's not the problem. In theory, some systems may implement integers with padding bits, trap representations and other obscure stuff. So if you alter the int through the char pointer and then attempt to do something with the int afterwards, the program might crash on such obscure systems. In practice, almost every single system out there is a two's complement system where every bit combination of an int is valid. – Lundin Nov 13 '15 at 10:48
  • @Lundin:out of curiosity can you link to standard or some other link? – Giorgi Moniava Nov 13 '15 at 10:51
  • 1
    It's a system-dependent hack to force bits 8-15 to 00000001. Any particular reason why the owner of the code wanted to do it like that? It's not like `a = (a & ~0xFF00) | 0x0100` is slow? – Andy Brown Nov 13 '15 at 11:03
  • 1
    @unwind it's `sizeof(char) <= sizeof(short) <= sizeof(int)` – 101010 Nov 13 '15 at 11:05
  • @101010 D'oh. Right. I deleted my comment. Thanks. – unwind Nov 13 '15 at 11:12
  • @unwind:did your opinion change about it being ub? – Giorgi Moniava Nov 13 '15 at 11:16
  • 1
    @Giorgi Yeah, I had the wrong idea that `sizeof (int) > sizeof (char)` is true, but that should be `>=` which makes code accessing the second `char` of an `int` potentially UB. – unwind Nov 13 '15 at 11:50
  • @Giorgi The C standard 6.2.6.2. – Lundin Nov 13 '15 at 12:02
  • @Lundin:hm I read that but it doesn't say exactly what you meant - probably you need to infer it. Here: http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule/99010#99010, answer also says you could use char to alias objects. Might be I am missing something – Giorgi Moniava Nov 13 '15 at 12:17
  • @Giorgi See my very first comment, aliasing is not the problem, but the signed integer format. Anyway, no point in derailing this question with all these comments, feel free to post a separate question. – Lundin Nov 13 '15 at 12:48

2 Answers2

3

cout << (int *) p << endl; would be the same as cout << &a << endl; (just the address of a).

int a = 2;
cout << sizeof(a) << endl;       // 4 (int is 4 bytes)
cout << sizeof(&a) << endl;      // 8 (64b machine, so pointer is 8 bytes)

char *p = (char *) &a;           // p points to first byte of a (normally 4 bytes)
cout << (int) *p << endl;        // 2    // Little Endian, the first byte is actually the last
cout << (int) *(p + 1) << endl;  // 0

*(p + 1) = 1;                    // second byte of a is now set to 1
cout << a << endl;               // a now changes to 258 (0000 0001 0000 0010)
artm
  • 17,291
  • 6
  • 38
  • 54
2

PS : If I want to show the value of p it shows only 2 not 258 how I expected.

The value of p is the address of the object to which it points. It seems your confusion is here. If you dereference p you will get value of object to which it points, that is different.

Hence, in your case p is initialized to address of a. Afterwards, nothing is assigned to it (e.g. nowhere you do p=&SomeOtherObject).

   cout << (int *) p << endl; // Print value of pointer -which is address

So above you are printing value of p which is address of a.

As noted keep in mind

*(p+1) = 1

might be undefined behaviour if sizeof (int) is same as sizeof (char)

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90