Overflow integer yang tidak ditandai didefinisikan dengan baik oleh standar C dan C ++. Misalnya, standar C99 ( §6.2.5/9
) menyatakan
Suatu perhitungan yang melibatkan operan tak bertanda tidak pernah dapat meluap, karena hasil yang tidak dapat diwakili oleh tipe integer tak bertanda yang dihasilkan dikurangi modulo angka yang satu lebih besar dari nilai terbesar yang dapat diwakili oleh jenis yang dihasilkan.
Namun, kedua standar menyatakan bahwa integer overflow yang ditandatangani adalah perilaku yang tidak terdefinisi. Sekali lagi, dari standar C99 ( §3.4.3/1
)
Contoh perilaku yang tidak ditentukan adalah perilaku pada aliran bilangan bulat
Apakah ada alasan historis atau (bahkan lebih baik!) Untuk perbedaan ini?
c++
c
undefined-behavior
integer-overflow
Anthony Vallée-Dubois
sumber
sumber
if (a + b < a)
). Overflow pada multiplikasi sulit untuk tipe yang ditandatangani dan tidak ditandatangani.MAX_INT+1 == -0
,, sedangkan pada komplemen dua akanINT_MIN
Jawaban:
Alasan historisnya adalah bahwa sebagian besar implementasi C (kompiler) hanya menggunakan perilaku luapan apa pun yang paling mudah diterapkan dengan representasi integer yang digunakannya. Implementasi C biasanya menggunakan representasi yang sama yang digunakan oleh CPU - jadi perilaku overflow diikuti dari representasi integer yang digunakan oleh CPU.
Dalam praktiknya, hanya representasi untuk nilai-nilai yang ditandatangani yang mungkin berbeda sesuai dengan implementasinya: komplemen satu, komplemen dua itu, magnitudo tanda. Untuk tipe unsigned, tidak ada alasan standar untuk mengizinkan variasi karena hanya ada satu representasi biner yang jelas (standar hanya mengizinkan representasi biner).
Kutipan yang relevan:
C99 6.2.6.1:3 :
C99 6.2.6.2 ::
Saat ini, semua prosesor menggunakan representasi pelengkap dua, tetapi limpahan aritmatika yang ditandatangani tetap tidak terdefinisi dan pembuat kompiler menginginkannya tetap tidak terdefinisi karena mereka menggunakan undefinedness ini untuk membantu pengoptimalan. Lihat misalnya posting blog ini oleh Ian Lance Taylor atau keluhan ini oleh Agner Fog, dan jawaban atas laporan bug-nya.
sumber
Selain jawaban yang baik dari Pascal (yang saya yakin adalah motivasi utama), ada kemungkinan juga bahwa beberapa prosesor menyebabkan pengecualian pada integer overflow yang ditandatangani, yang tentu saja akan menimbulkan masalah jika kompilator harus "mengatur perilaku lain" ( mis. gunakan instruksi tambahan untuk memeriksa potensi luapan dan menghitung secara berbeda dalam kasus itu).
Perlu juga dicatat bahwa "perilaku tidak terdefinisi" tidak berarti "tidak bekerja". Ini berarti bahwa implementasi diperbolehkan untuk melakukan apa pun yang disukainya dalam situasi itu. Ini termasuk melakukan "hal yang benar" serta "memanggil polisi" atau "menabrak". Kebanyakan kompiler, jika memungkinkan, akan memilih "melakukan hal yang benar", dengan anggapan bahwa itu relatif mudah untuk didefinisikan (dalam hal ini, itu). Namun, jika Anda mengalami luapan dalam perhitungan, penting untuk memahami apa yang sebenarnya dihasilkan, dan bahwa kompiler MUNGKIN melakukan sesuatu selain dari yang Anda harapkan (dan bahwa ini mungkin sangat tergantung pada versi kompiler, pengaturan optimasi, dll) .
sumber
int f(int x) { return x+1>x; }
dengan optimasi. GCC dan ICC lakukan, dengan opsi default, mengoptimalkan di atasreturn 1;
.int
luapan tergantung pada tingkat optimisasi, lihat ideone.com/cki8nM Saya pikir ini menunjukkan bahwa jawaban Anda memberikan saran yang buruk.Pertama-tama, harap dicatat bahwa C11 3.4.3, seperti semua contoh dan catatan kaki, bukan teks normatif dan karenanya tidak relevan untuk dikutip!
Teks yang relevan yang menyatakan bahwa overflow bilangan bulat dan float adalah perilaku yang tidak didefinisikan adalah ini:
C11 6.5 / 5
Klarifikasi mengenai perilaku tipe bilangan bulat yang tidak ditandatangani secara spesifik dapat ditemukan di sini:
C11 6.2.5 / 9
Ini membuat tipe integer yang tidak ditandai sebagai kasus khusus.
Perhatikan juga bahwa ada pengecualian jika jenis apa pun dikonversi ke jenis yang ditandatangani dan nilai lama tidak lagi dapat diwakili. Perilaku ini kemudian hanya implementasi-didefinisikan, meskipun sinyal dapat dinaikkan.
C11 6.3.1.3
sumber
Selain masalah lain yang disebutkan, memiliki bungkus matematika yang tidak ditandatangani membuat tipe integer yang tidak ditandatangani berperilaku sebagai kelompok aljabar abstrak (artinya, antara lain, untuk setiap pasangan nilai
X
danY
, akan ada beberapa nilaiZ
lain yangX+Z
akan, jika dilemparkan dengan benar , sama ). Jika nilai yang tidak ditandatangani hanyalah tipe lokasi penyimpanan dan bukan tipe ekspresi menengah (mis. Jika tidak ada padanan unsigned dari tipe integer terbesar, dan operasi aritmatika pada tipe unsigned berperilaku seolah-olah mereka pertama kali mengonversikannya ke tipe yang ditandatangani lebih besar, maka ada tidak akan sebanyak kebutuhan untuk perilaku pembungkus yang ditentukan, tetapi sulit untuk melakukan perhitungan dalam jenis yang tidak memiliki mis invers tambahan.Y
danY-Z
akan, jika dilemparkan dengan benar, samaX
Ini membantu dalam situasi di mana perilaku wrap-around sebenarnya berguna - misalnya dengan nomor urut TCP atau algoritma tertentu, seperti perhitungan hash. Mungkin juga membantu dalam situasi di mana perlu untuk mendeteksi luapan, karena melakukan perhitungan dan memeriksa apakah meluap sering lebih mudah daripada memeriksa di muka apakah akan meluap, terutama jika perhitungan melibatkan tipe bilangan bulat terbesar yang tersedia.
sumber
a+b-c
dihitung dalam satu loop, tetapib
danc
konstan dalam loop itu, mungkin akan membantu untuk memindahkan perhitungan di(b-c)
luar loop, tetapi melakukan hal itu akan membutuhkan di antara hal-hal lain yang(b-c)
menghasilkan nilai yang, ketika ditambahkan kea
, akan menghasilkana+b-c
, yang pada gilirannya mengharuskan yangc
memiliki aditif terbalik.(a+b)-c
sama dengana+(b-c)
apakah nilai aritmatikab-c
dapat diwakili dalam tipe, substitusi akan valid terlepas dari rentang nilai yang dimungkinkan untuk(b-c)
.Mungkin alasan lain mengapa aritmatika unsigned didefinisikan adalah karena bilangan unsigned membentuk bilangan bulat modulo 2 ^ n, di mana n adalah lebar bilangan unsigned. Angka yang tidak ditandai hanyalah bilangan bulat yang direpresentasikan menggunakan digit biner alih-alih digit desimal. Melakukan operasi standar dalam sistem modulus dipahami dengan baik.
Kutipan OP mengacu pada fakta ini, tetapi juga menyoroti fakta bahwa hanya ada satu, cara yang jelas, logis untuk mewakili bilangan bulat tidak bertanda dalam biner. Sebaliknya, angka yang ditandatangani paling sering direpresentasikan menggunakan komplemen dua tetapi pilihan lain dimungkinkan seperti yang dijelaskan dalam standar (bagian 6.2.6.2).
Representasi komplemen dua memungkinkan operasi tertentu untuk lebih masuk akal dalam format biner. Misalnya, penambahan bilangan negatif sama dengan bilangan positif (perkirakan dalam kondisi luapan). Beberapa operasi di level mesin bisa sama untuk nomor yang ditandatangani dan tidak ditandatangani. Namun, ketika menginterpretasikan hasil dari operasi tersebut, beberapa kasus tidak masuk akal - luapan positif dan negatif. Selain itu, hasil melimpah berbeda tergantung pada representasi yang ditandatangani yang mendasarinya.
sumber