3

I'm an IT student and today I had a C programming exam. One of questions is a bit confusing: Is it possible to cast float* to int* ? I said no whats your opinion?

Christopher Neylan
  • 7,455
  • 3
  • 34
  • 50
  • you can and you can't: check out static_cast and reinterpret_cast – BeyelerStudios Jan 08 '15 at 14:12
  • @BeyelerStudios that's C++, no? – Christopher Neylan Jan 08 '15 at 14:27
  • 3
    "whats your opinion?" -- There's no opinion to it. It is possible to cast `float*` to `int*`. It might not do what you expect from it, but that doesn't make it invalid or impossible to do ;) – Magnus Hoff Jan 08 '15 at 14:33
  • It is, but it is potentially unsafe, as it breaks [strict-aliasing rule](http://en.wikipedia.org/wiki/Pointer_aliasing). In addition to that, the C-language standard does not impose `sizeof(int)` and `sizeof(float)` being equal. So on a given platform, if they are not equal, then it is unsafe even without breaking strict-aliasing rule (using the pointer in order to access memory yields undefined behavior). – barak manos Jan 08 '15 at 14:36
  • Take a look [here](http://en.wikipedia.org/wiki/Fast_inverse_square_root) where this was used in actual production code. – Degustaf Jan 08 '15 at 15:09
  • @ChristopherNeylan yes, at that time OP didn't specify `C` – BeyelerStudios Jan 08 '15 at 16:01

2 Answers2

4

You can cast, but you won't magically get an integer version of the float.

What happens is that you have a float somewhere in memory and then have an integer point to the same location. But the two are represented differently (e.g., two's complement vs IEEE 754), and you will get a vastly different integer as a result.

For example:

#include <stdio.h>

int main() {
  printf("sizeof(int) = %zu\n", sizeof(int));
  printf("sizeof(float) = %zu\n", sizeof(float));

  float m = 456.78f;
  int *p = (int*)&m;

  printf("Float:   %f\n", m);
  printf("Integer: %d\n", *p);

  return 0;
}

On my system, this outputs:

sizeof(int) = 4
sizeof(float) = 4
Float:   456.779999
Integer: 1139041239

I print their sizes as well, to emphasize that they could be different as well. E.g., if the integer happened to be larger, you would then touch memory outside of the float.

While this is probably not what you want, there are uses for it. For example, if you want to see the bit-representation for a specific float, you could cast it to something like uint8_t and inspect it up to sizeof(float).

csl
  • 10,108
  • 5
  • 51
  • 86
  • 1
    I think that the `printf("sizeof(int) = %lu\n", sizeof(int))` is potentially unsafe by itself. I'm not sure what the standard says about `size_t`, but if `long` is 8 bytes and `size_t` is 4 bytes on your platform, then this call to `printf` is a source of trouble. There is probably a safer (and more portable) way of writing it. According to [this answer](http://stackoverflow.com/a/587032/1382251) you should use `"%z"`). – barak manos Jan 08 '15 at 14:42
  • Thanks, you're right. I changed it from `%lu` to `%zu` as recommended in http://stackoverflow.com/questions/3168275/printf-format-specifiers-for-uint32-t-and-size-t (I knew about `PRIu` but not `%z` actually, thanks for the tip!) – csl Jan 08 '15 at 14:45
  • You're welcome. I just learned about this myself, googling "print size_t in c" :) – barak manos Jan 08 '15 at 14:47
2

Why not just try it out?

$ cat foo.c
#include <stdio.h>
int main(){
  float f = 0.15625;
  float *p = &f;
  printf("%f\n", *p);
  printf("%i\n", *((int *)p));
}
$ gcc foo.c
$ ./a.out
0.156250
1042284544

The float is 32-bits and you can read about how its represented: http://en.wikipedia.org/wiki/Single-precision_floating-point_format

Casting the float pointer to an int pointer is just telling C that "the data I'm pointing to is an int".

The float 0.156250 is represented by the binary 0111110001000000000000000000000, which represents the integer 1042284544.

EDIT: @csl beat me to the answer :)

Christopher Neylan
  • 7,455
  • 3
  • 34
  • 50