2

I'm trying to understand pointers, their values and types

let's say I have an int x:

int x = 0;
int* ip = &x; 

I know the value here is the address of x, let's say it is 123.

*ip += 1 

Is the value now 124? (the address + 1). I'm trying to understand what happens to the value and type here:

float *fp = (float*)ip; 
*fp = 1.0; 
int y = *ip;
TylerH
  • 20,799
  • 66
  • 75
  • 101
alpitaka
  • 55
  • 6
  • 2
    Undefined behavior because of [strict aliasing rule](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) – kiran Biradar Jan 24 '19 at 07:49
  • Whilst you are casting ip to fp, the modified content of ip after the *fp = 1.0 assignment will not be correct as the storage for an integer is completely different from the storage of a float. An int is either 16 bit or 32 bit according to the system, a float is always 32 bits. – SPlatten Jan 24 '19 at 07:53
  • 1
    @SPlatten: Not quite; 64 bit `int` are appearing now (other sizes are rare but they are out there), and a `float` can be the same size as a `double`. – Bathsheba Jan 24 '19 at 07:57
  • @Bathsheba, I'm not so certain of that. Annex F of C11 (which is normative) specifically states which types equate to float and double: "The float type matches the IEC 60559 single format" and "The double type matches the IEC 60559 double format". – paxdiablo Jan 24 '19 at 08:00
  • @Bathsheba, true, as I said in my post, an integer depends on the system. Floats are normally 4 bytes (32 bits) where as a double is 8 bytes (64 bits). – SPlatten Jan 24 '19 at 08:01
  • Possible duplicate of [What does "dereferencing" a pointer mean?](https://stackoverflow.com/questions/4955198/what-does-dereferencing-a-pointer-mean) – Andreas is moving to Codidact Jan 24 '19 at 08:12
  • @alpitaka Since you're a new member of StackOverflow, I'll remind you that you can select your favorite answer to your question. – okovko Jan 24 '19 at 08:50
  • 1
    @paxdiablo: Annex F is optional. – Eric Postpischil Jan 24 '19 at 12:19
  • @Eric, good point, I should have read further, to the bit that mentions it only holds if an implementation defines `__STDC_IEC_559__`. – paxdiablo Jan 24 '19 at 13:58

2 Answers2

3

If you set a pointer to the address of a variable and then do a dereference assignment, you will change the value at the pointer, not the address itself. So if you write ip += 1 that changes the address, and *ip +=1 changes the value at the address.

Here's a bunch of examples that should help make it clear how pointers work, including with floating point values. You should read about the IEEE754 representation of 32 bit floats to understand better why 1.0 is represented as 0x3f800000.

Please note that this code makes a lot of assumptions about the sizes of types (which are implementation defined!) and disregards aliasing rules (it is not allowed to point to an object in memory with a pointer type that does not match the declared type of the object and then dereference that pointer). That said, in practice, you can always interpret any memory as bits, even if it is "unsafe" or "illegal".

int x = 0;
int* ip = &x;
*ip += 1; // x = 1
ip += 1; // ip is now increased by sizeof(int) and probably points to
        // the gap in the stack between x and ip, since sizeof(x) is probably 4
        // and ip is probably 8 byte aligned
ip += 1; // now ip probably points to itself! (the address points to its own address value)
ip -= 2; // now ip points to x again
*ip += 2; // now x = 3

float *fp = (float*)ip; // the value *fp is the same in binary, 0b11
int z = *(int *)fp;    // z is 3, because we're preventing the conversion
*fp = 1.0;            // in hex, *fp is 0x3f800000
int y = *fp;         // 1.0 is converted to int and stored in y as 1
int a = *(int *)fp; // a is 0x3f800000
okovko
  • 1,851
  • 14
  • 27
  • 1
    This answer is missing mention of strict aliasing violations, and that type based alias analysis must be disabled on the compiler before this code can work reliably. – user694733 Jan 24 '19 at 08:38
  • @user694733 I'm just trying to demonstrate a bunch of cases that make it clear how pointers work in relation to their types. I used the word `probably` everywhere, so I thought it was clear :p but I will add a note. – okovko Jan 24 '19 at 08:40
  • @SanderDeDycker Please advise / correct me if I'm mistaken trying to talk about aliasing rules. I program like everything is `void *` 8) – okovko Jan 24 '19 at 08:45
  • 1
    @okovko : minor nitpick : you can point to an object with an incompatible pointer type - it's accessing the pointed-to value through an incompatible pointer that gives undefined behavior. A [good write-up](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule). – Sander De Dycker Jan 24 '19 at 08:56
  • @SanderDeDycker I edited that in, thanks. I'll read that link, leave your comment up because I'll read it tomorrow. – okovko Jan 24 '19 at 08:58
  • *"it is not allowed since C11"* Aliasing rules are not limited to C11, all standardized versions have it. (Earliest I found was C90, but C89 also has it I think) *"in practice, you can always interpret any memory as bits"* Unfortunately that really isn't true. I have worked on compilers where your code may break if you compile with default settings. If you want to reinterpret memory, you need to use only safe types or take the extra work to adjust compiler settings. "It seems to work, and I haven't checked why" is a landmine waiting to blow up. – user694733 Jan 24 '19 at 09:05
  • @user694733 Thanks, I thought the rules were changed to harmonize with C++ or something. As for your other point, I don't know, who cares if that land mine blows up? You get a compile time error and you fix it in five seconds by adding a compiler flag. The spirit of C is somewhat lost in modern compilers, but at its heart, C is a language that reflects the machine model. If you program according to the machine model, then you're safe. But that requires spending time understanding the machine model instead of C standards :P – okovko Jan 24 '19 at 09:53
  • 1
    *"You get a compile time error and you fix it in five seconds by adding a compiler flag."* Problem is that you **don't** get compile time error. Strict aliasing affects how compiler generates instructions. One example of the issue could be that compiler doesn't refresh value of the variable from memory to CPU register, because it assumed that variable couldn't have been modified since it was last referenced. Seemingly innocent change elsewhere can cause missing instruction and the code stops working as intended. That is why strict aliasing issues are so painful to deal with. – user694733 Jan 24 '19 at 10:03
  • @user694733 Thanks for sharing. I'll bear that in mind. – okovko Jan 24 '19 at 10:13
0
int x = 0;
int* ip = &x;  /*I know the value here is the address of x, let's say it is 123*/
printf("\n%u",ip); //value is 123
printf("\n%u",*ip);// value is 0
*ip += 1; //*ip points to the value of the stored address i.e. x and increase it by 1 
printf("\n%u",ip); //value is 123
printf("\n%u",*ip); //value is 1

float *fp = (float*) ip; converting address inside ip i.e. 123 into float type and store in fp
printf("\n%u",fp); //value is 123
printf("\n%f",*fp);//points to the value of stored address i.e. value at 123. 0.000000 is the value as we have converted it to float from int it got initialized to 0
*fp = 1.0; //storing the value to address 123

printf("\n%f",*fp);//value is 1.000000
int y = *ip;//storing the value

printf("\n%f",y);//it will also gives 1.000000

Am not explaining internal conversions between float and int here. Just explaining how pointer works

Rock
  • 101
  • 3
  • 15