0

I have a C Syntax 101 question. Suppose I have a function which takes one kind of pointer as a argument and returns a different type of pointer, and both pointers point to the same data from within the calling function. For example:

#include <stdio.h>

float* convertPtr(const int *a){
  return (float*)a;
}

int main() {
  float *ptrF;
  int x = 5;

  ptrF = convertPtr(&x);
  printf("%d ::converted to::  %f\n", x, *ptrF);
  return 0;
}

Output of this program is:

5 ::converted to::  0.000000

So I'm a bit baffled by this. The original data is created within main() and is not changed. The convertPtr() function never alters the data, but should only change the type of the pointer.

I also note that when I step through the code on GDB, the pointer (the address itself) does not change:

Breakpoint 1, main () at exp.c:9
9         int x = 5;
(gdb) p &x
$3 = (int *) 0x7fffffffe224
...continue to after calling convertPtr()...
(gdb) p ptrF
$4 = (float *) 0x7fffffffe224
(gdb)

Yet the value pointed to that data has:

(gdb) p x
$8 = 5
(gdb) p *(&x)       // sanity check
$9 = 5
(gdb) p *ptrF
$10 = 7.00649232e-45
(gdb)

So... what the heck? After my convertPtr() function, the pointer has been recast but the value of the pointer has not changed... yet dereferencing the converted pointer seems to be pointing to garbage data. (I'm assuming.)

Does anyone see the issue here? Supposed I HAD to fix my function; how do I do that? Thanks...

-ROA

PS: Apologies if this is a duplicate question. I searched for about an hour for "C", "pointer", "casting", "change value", and the posts I pulled up were all over the map. Sometimes its best to ask your question directly.

Pete
  • 1,511
  • 2
  • 26
  • 49
  • 1
    `x` is an `int`. When you force the address to point to a `float`, it still contains the bits of an `int`. That's not a `float`. And, as explained in the answer, it's undefined behavior anyway as you're violating the strict aliasing rule. Try doing that on some systems and you'll likely get a `SIGBUS` or similar that aborts your program. – Andrew Henle Apr 05 '17 at 14:09
  • Compare `p /t x` and `p /t *ptrF` instead. (Then think about the concepts of *representation* and *interpretation* until you get it.) – molbdnilo Apr 05 '17 at 14:12
  • @AndrewHenle Wow, thanks Andrew, that makes a world of sense. I hadn't thought about the bit structure of an int vs. a float. That also explains how I was able to do this earlier between an int and an unsigned short. Much appreciated! – Pete Apr 05 '17 at 16:10
  • @molbdnilo. Hmm, awesome suggestion, thanks, I'll try it – Pete Apr 05 '17 at 16:10

1 Answers1

1

In your code

 return (float*)a;

is violation of strict aliasing rule. An int * and a float * do not alias each other, so the casting makes the code invalid.

int and float have different alignment requirements, so basically you cannot reference the memory location reserved for an int via a pointer to float (and vice-versa) and expect everything to fall into place.

Quoting the relevant part of the standard, chapter §6.5/P7

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)

— a type compatible with the effective type of the object,

— a qualified version of a type compatible with the effective type of the object,

— a type that is the signed or unsigned type corresponding to the effective type of the object,

— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,

— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or

— a character type.

and, more, chapter §6.3.2.3/P7

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined. [....]

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    The clause about alignment of the pointed-to type is certainly a consideration, and it *might* be relevant, but if there is any singular *the* relevant part of the standard then it is surely [paragraph 6.5/7](http://port70.net/~nsz/c/c11/n1570.html#6.5p7), a.k.a. the Strict Aliasing Rule. – John Bollinger Apr 05 '17 at 14:20
  • @JohnBollinger actually that makes much more sense, let me add that too alogside my own words. :) – Sourav Ghosh Apr 05 '17 at 14:31
  • @SouravGhosh - Thanks Sourav, I wasn't familiar with the term "strict aliasing" I'm going to read up on your recommendations... – Pete Apr 05 '17 at 16:08
  • @SouravGhosh - Thanks, your readings led me to the answer. I've modified my function to malloc() a float on the heap, then assign the value of the incoming int to the new float. This ensures the returned float* points to something with the original data.... I just have to remember to free() the pointer in the main() function. – Pete Apr 05 '17 at 16:14