Casting from double always returns zero

Viewed 149

Why does the following code returns zero, when compiled with clang?

#include <stdint.h>
uint64_t square() {
    return ((uint32_t)((double)4294967296.0)) - 10;
}

The assembly it produces is:

    push    rbp
    mov     rbp, rsp
    xor     eax, eax
    pop     rbp
    ret

I would have expected that double to become zero (integer) and that minus would wrap it around. In other words, why doesn't in matter what number there is to subtract, as it always produces zero? Note that gcc does produce different numbers, as expected:

    push    rbp
    mov     rbp, rsp
    mov     eax, 4294967285
    pop     rbp
    ret

I assume casting 4294967296.0 to uint32_t is undefined behaviour but even then, I would expect to produce different results for different subtrahends.

2 Answers

The behaviour of casting an out-of-range double to an unsigned type is indeed undefined.

Wrap-around does not apply, even for an unsigned type.

This is an oft-forgotten rule.

Once program control reaches an undefined construct, the entire program is undefined, even somewhat paradoxically, statements that have already been ran.

Reference: https://timsong-cpp.github.io/cppwp/conv.fpint#1

g++ 5.4.0 gives 4294967285 (-11 unsigned), so it is up to the compiler what it wants to do with undefined behavior.

__Z6squarev:
LFB1023:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        movl    $-11, %eax
        movl    $0, %edx
        popl    %ebp
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
Related