3

The expression

#define __HI(x) *(1+(int*)&x)

is defined in Sun's math library, in fdlibm.h. It is used in most programs of Sun's math library, e.g., in its implementation of sin(x)

    double y[2],z=0.0;
    int n, ix;

    /* High word of x. */
    ix = __HI(x);

    /* |x| ~< pi/4 */
    ix &= 0x7fffffff;
    if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);

In the code above, variable x is of type double. Can any one explain me the syntax the expression in __HI(x). The readme of Sun's library says __Hi(x) is

"the high part of a double x (sign,exponent,the first 21 significant bits)".

I just do not understand the syntax of *(1+(int*)&x), and why it corresponds to x 's higher part. Any clarification?

zell
  • 9,830
  • 10
  • 62
  • 115
  • 2
    It produces undefined behavior. – R.. GitHub STOP HELPING ICE Aug 30 '15 at 19:53
  • @R..: As much as some required OS-code does? – too honest for this site Aug 30 '15 at 20:03
  • 2
    @Olaf More than that. It violates strict aliasing rules, so the compiler is not required to retain the order of reads/writes to `__HI(x)` and `x`. This is not just the implementation defined behavior that's needed to interact with the implementation. Also note that the macro is not guarded sufficiently. Both `__HI(x + 3)` and `__HI(x)[y]` will not do what a reader would think they do. – cmaster - reinstate monica Aug 30 '15 at 20:22
  • @cmaster: It is UB with respect to the standard and the abstract machine - sure. The execution environment, however has exact knowledge what the "thing which executes the program" (aka CPU/hardware) does. Of course this requires coordination with the code-generator. This is actually the reason to use C here: because you do what you want, as long as you really consider **all** implications. – too honest for this site Aug 30 '15 at 20:29
  • Just to state clear: this is nothing one should do in one's own application code. On bare-metal embedded system, sometimes you have to, however. And if I find something like that without justification in a student's code, he will be punished with not less than 3 weeks. – too honest for this site Aug 30 '15 at 20:30
  • 4
    The actual code is inherited in many OSes, including most BSD-based distributions, and with some strategic googling, you should be able to observe that in the more standard-conscious places where it ended up, the macro `__HI` was replaced with something more standards-compliant: ftp://ftp.irisa.fr/pub/OpenBSD/src/lib/libm/src/math_private.h – Pascal Cuoq Aug 30 '15 at 20:35
  • 1
    @Olaf Nonsense. A compiler will “miscompile” code that ignores strict aliasing rules whatever the author of the code thinks the code should do on the targeted platform, low-level code or otherwise. All the time the author of the code will spend investigating the “miscompilation bug” will be wasted because the authors of the compiler will only tell them that they deserved it. The authors of the code will be left with writing a sour blog post and calling the authors of the compiler incompetent. This has happened multiple times in the past, references available on request. – Pascal Cuoq Aug 30 '15 at 20:42
  • 1
    It's called `__HI`, which is a name reserved by the standard. You already get UB by defining something called `__HI` regardless of its content. – tmyklebu Aug 30 '15 at 21:19
  • @PascalCuoq: We already need to specify `-fno-strict-aliasing` when we're writing networking code. I've never seen the results of alias analysis meaningfully improve a program's performance, so it doesn't seem unreasonable to me to use `-fno-strict-aliasing` everywhere. – tmyklebu Aug 30 '15 at 21:22

1 Answers1

4

This:

*(1+(int*)&x)

Means: Take the address of x (&x), cast it as a pointer-to-int (int*), add 1, and dereference the resulting pointer. Assuming that Sun is using this format, this means that the value in memory looks like:

<sign (1 bit)><exponent (11 bits)><significand (52 bits)>

If sizeof(int) is 32 bits, this will find the location of the double in memory, then increment the pointer to the next int, which contains the sign, exponent, and first 21 bits of the number.

larsks
  • 277,717
  • 41
  • 399
  • 399