Приведение из двойного всегда возвращает ноль - PullRequest
3 голосов
/ 31 марта 2020

Почему следующий код возвращает ноль при компиляции с помощью clang?

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

Сборка, которую он производит:

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

Я бы ожидал, что double станет равным нулю ( целое число) и этот минус обернул бы его вокруг. Другими словами, почему не важно, какое число нужно вычесть, так как оно всегда дает ноль? Обратите внимание, что g cc производит разные числа, как и ожидалось:

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

Я предполагаю, что приведение от 4294967296.0 к uint32_t - это неопределенное поведение, но даже в этом случае я ожидаю получить разные результаты для разных вычитаемых.

Ответы [ 2 ]

15 голосов
/ 31 марта 2020

Поведение приведения вне диапазона double к типу unsigned действительно не определено .

Обтекание не применяется даже для типа unsigned.

Это часто забываемое правило.

Когда управление программой достигает неопределенной конструкции, вся программа становится неопределенной, даже несколько парадоксально, операторами, которые имеют уже был запущен.

Ссылка: https://timsong-cpp.github.io/cppwp/conv.fpint#1

0 голосов
/ 31 марта 2020

g ++ 5.4.0 выдает 4294967285 (-11 без знака), поэтому компилятор должен решать, что он хочет сделать с неопределенным поведением.

__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
...