Mengapa di C ++ lakukan static_cast <unsigned> dari angka negatif berbeda jika jumlahnya konstan atau tidak

28

Apa C ++ aturan yang berarti sama adalah palsu ?. Diberikan:

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

Misalnya 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;
}

Menghasilkan output berikut:

 f=ffffffff
cf=0
GreyMattR
sumber
6
Punya suara positif: Anda telah tertangkap oleh aturan yang sering dilupakan tentang perilaku yang tidak terdefinisi!
Batsyeba
Hasil apa yang Anda harapkan untuk mengubah float negatif menjadi yang tidak ditandatangani?
Amadeus
1
@Amadeus mungkin membungkus yang biasa kita dapatkan ketika mengkonversi bilangan bulat negatif. Saya harus memeriksa bahwa itu adalah UB karena itu mengejutkan saya.
Pemrogram
1
@Amadeus, itu lebih merupakan kasus memahami perbedaan. Saya memperbaiki kesalahan ketik beberapa minggu yang lalu ... sebuah konstanta float secara eksplisit dilemparkan ke unsigned (bug), dan secara implisit kembali ke yang ditandatangani (sebagai parameter fungsi yang ditandatangani). Saya kemudian merenungkan mengapa bug asli menyebabkan nilai nol dalam fungsi. Pengujian menunjukkan itu karena float adalah const. Pelampung non-const yang secara eksplisit dilemparkan ke unsigned dan kemudian secara implisit dilemparkan kembali untuk ditandatangani tidak menghasilkan bahaviour yang sama - non-cast non-const memiliki nilai asli dan yang diharapkan.
GreyMattR

Jawaban:

26

Perilaku program Anda tidak terdefinisi : standar C ++ tidak mendefinisikan konversi tipe floating point negatif ke suatu unsignedtipe.

(Perhatikan perilaku lilitan yang sudah dikenal hanya berlaku untuk tipe integral negatif .)

Jadi karena itu ada gunanya mencoba menjelaskan output program Anda.

Batsyeba
sumber
1
Apakah ini didefinisikan jika saya akan mengkonversi float-> int-> unsigned?
Yksisarvinen
5
@Yksisarvinen: Hanya jika floatberada dalam kisaran suatu int.
Batsyeba
Saya menerima bahwa UB adalah jawaban yang benar, dan seharusnya menjadi akhir dari itu ... tetapi mengingat bahwa ... Apa jawaban kompiler-penulis yang menjelaskan mengapa semua kompiler pada Compiler Explorer (dentang / gcc / djgpp) menghasilkan output setara (UB)?
GreyMattR
5
@GreyMattR Jika kompilator dapat membuktikan bahwa nilai dijamin menjadi negatif pada saat pemeran, maka ia dapat meninggalkan hasil pemeran tidak diinisialisasi, atau mengaturnya ke nol, atau apa pun yang ingin dilakukan. Jika kompiler tidak dapat membuktikannya, ia harus membuat kode untuk melakukan pemeran. Untuk tujuan tersebut, dapat menggunakan kembali kode untuk dilemparkan ke tipe integer yang telah ditandatangani (hasilnya hanya akan "salah" jika para pemainnya adalah UB, yang berarti itu sebenarnya tidak salah). Dengan optimasi yang lebih agresif, para pemain tidak akan dipancarkan dalam kasus non-const juga.
Brian
@Brian, terima kasih atas penjelasan yang bermanfaat itu.
GreyMattR