-2

What do the asterisks in this C language macro do?

#define asreal(x) (*((float *) &x))

I know about pointers in C, but it seems like the asterisks in this macro are being used for arithmetic? I am not sure exactly what is happening here.

Is the &x bitwise result being cast to a float pointer? Then why is there an additional asterisk outside of that expression?

jhaubrich.com
  • 79
  • 2
  • 10
  • 1
    It means the same thing it means if this wasn't a macro. Can you explain why you believe these asterisks are used for arithmetic? Doesn't it take two to tango, for arithmetic? You have to have two things to multiply together, and I only see one object here. P.S. There is no need to write macros in modern C++, but if you ever do, don't write anything like that, for at least two different reasons. – Sam Varshavchik Apr 17 '22 at 18:54
  • Yes I am aware the arithmetic operators take 2 operands. I am familiar with how pointers work in C but have never seen them used inside of the expression like this, with 2 asterisks not just one. I am not writing a macro like this, just reading an example out of a book that has left me a but perplexed. Is the &x bitwise result being cast to a float pointer? Then why is there an additional asterisk outside of that expression? – jhaubrich.com Apr 17 '22 at 18:56
  • Well, whichever book that is, you should probably avoid reading much more from it. This macro showcases laughably amateurish mistakes, when it comes to macros. It makes the same mistake, for example, as the classic `#define multiply(a,b) (a*b)`: if you call `multiply(1+2,3)` the result will not be 9. So, even as an example of macros, this is a horrible example. And the underlying concept (type punning) is even more horrible. It's hard to decide which part of this is is the most horrible. – Sam Varshavchik Apr 17 '22 at 18:59
  • The book is called 'Understanding the Machine', I am reading a chapter about floating point numbers. I understand it may be a horrible example, but I am not asking about whether or not such a macro is in best practice or not, I am simply trying to understand why there are multiple asterisks and what they are doing! – jhaubrich.com Apr 17 '22 at 19:02

1 Answers1

2

&x - take address of x

(float*) &x - cast it to float*

*((float *) &x) dereference casted result (result type is float)

(*((float *) &x)) - wrap it in paranthesis so it doesn't interfere with outside code

So basically, the code takes bytes in x and reinterprets them as float. Note that this macro would only be useful if

  • x is a float already or
  • if it contains binary data equal to a valid float.

It cannot be used to convert int value to float (unless you try to use the bit representation of that int, not the value) It will also break if called like asreal(x + y) or in quite a lot of other possiblities. I'm also not sure if it's defined behaviour in C, but if you are trying to "understand the machine", you are probably ready for certain UBs.

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • Why is it necessary to take the address of x before casting it to a float? – jhaubrich.com Apr 17 '22 at 19:17
  • 1
    @jhaubrich.com You cast it to `float*`, not `float`. Basically, doing `(float) x` would tell the compiler "*please convert it to `float` as well as you can*", so converting `int x = 10;` would result in `float y = 10.0f;` (more or less). By moving to pointers, you tell compiler "*shut up about types, this memory sequence contains a `float`*". Converting `int x = 10;` will result in roughly `1.4e-44`, because this number has the same binary representation as integer with value `10`. – Yksisarvinen Apr 17 '22 at 19:36
  • 2
    It's undefined behaviour also if x is not of type float. Type puning with unions are defined in C. – Fredrik Apr 17 '22 at 19:38
  • @Fredrik I see. I'm not very fluent in C, that's good to know. I think it would be defined in C++ under a whole lot of conditions (alignment, implementation-specific `float` representation etc.), otherwise binary files would be impossible to use. – Yksisarvinen Apr 17 '22 at 19:52
  • 1
    @Yksisarvinen `(*((float *) &x))` is a [strict aliasing violation](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) if `x` is not a `float` and undefined behavior because of that, and if `x` is not ["correctly aligned"](https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7) it can also be undefined behavior for that reason. – Andrew Henle Apr 17 '22 at 20:20