Чому в C ++ різняться static_cast <без підписання> від'ємних чисел, якщо число постійне чи ні


28

Що за правила C ++, що означає рівне , помилково ?. Подано:

float f {-1.0};
bool equal = (static_cast<unsigned>(f) == static_cast<unsigned>(-1.0));

Наприклад, https://godbolt.org/z/fcmx2P

#include <iostream>

int main() 
{
          float   f {-1.0};
    const float  cf {-1.0};

    std::cout << std::hex;
    std::cout << " f" << "=" << static_cast<unsigned>(f) << '\n';
    std::cout << "cf" << "=" << static_cast<unsigned>(cf) << '\n';

    return 0;
}

Випускає такий вихід:

 f=ffffffff
cf=0

6
Майте нагороду: вас спіймало часто забуте правило про невизначену поведінку!
Вірсавія

Яких результатів ви очікуєте перетворення негативного поплавця в непідписаний?
Амадей

1
@Amadeus, ймовірно, звичайне обгортання, яке ми отримуємо при перетворенні від'ємного цілого числа. Я повинен був перевірити, що це UB, тому що це мене здивувало.
AProgrammer

1
@Amadeus, це було більше випадком розуміння різниці. Я виправив помилку помилки друку кілька тижнів тому ... const-float явно був переданий до безпідписаного (помилка), і неявно повернувся до підписаного (як параметр функції підписаного). Пізніше я розмірковував, чому початкова помилка викликала нульове значення у функції. Тестування говорить про те, що поплавок був const. Нестандартний поплавок, який явно був переданий непідписаним, а потім неявно повернутий до підписаного, не призвів до того ж поведінки - неодноразовий зміст, який був два рази, мав початкове і очікуване значення.
GreyMattR

Відповіді:


26

Поведінка вашої програми не визначена : стандарт C ++ не визначає перетворення негативного типу з плаваючою комою у unsignedтип.

(Зверніть увагу, що звична поведінка під час обгортання стосується лише негативних інтегральних типів.)

Отже, мало намагань пояснити вихід програми.


1
Чи визначено, чи замість цього я перетворять float-> int-> без підпису?
Yksisarvinen

5
@Yksisarvinen: Тільки якщо показник floatзнаходиться в межах int.
Вірсавія

Я погоджуюсь, що UB - це правильна відповідь, і так має бути в кінці ... але, враховуючи, що ... Яка ймовірна відповідь-компілятор, яка пояснює, чому всі компілятори на Провідник компілятора (clang / gcc / djgpp) видають еквівалентний (UB) вихід?
GreyMattR

5
@GreyMattR Якщо компілятор може довести, що значення гарантовано є негативним на момент виступу, тоді він може залишити результат неініціалізованого, або встановити його в нуль, або все, що він хоче зробити. Якщо компілятор не може цього довести, він повинен генерувати код, щоб виконати команду. Для таких цілей він може повторно використовувати код для додавання до підписаного цілочисельного типу (результат буде "неправильним" лише якщо команда UB, це означає, що це насправді неправильно). При більш агресивній оптимізації, амплуа також не випромінюватиметься у випадку non-const.
Брайан

@Brian, дякую за корисне пояснення.
GreyMattR
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.