Jawaban singkat
Anda i
akan dikonversi ke integer yang tidak ditandatangani dengan menambahkan UINT_MAX + 1
, maka penambahan akan dilakukan dengan nilai yang tidak ditandatangani, menghasilkan nilai yang besar result
(tergantung pada nilai-nilai u
dan i
).
Jawaban panjang
Menurut Standar C99:
6.3.1.8 Konversi aritmatika biasa
- Jika kedua operan memiliki tipe yang sama, maka tidak diperlukan konversi lebih lanjut.
- Jika tidak, jika kedua operan memiliki tipe integer yang ditandatangani atau keduanya memiliki tipe integer yang tidak ditandatangani, operan dengan jenis peringkat konversi integer yang lebih rendah dikonversi ke jenis operan dengan peringkat yang lebih besar.
- Sebaliknya, jika operan yang memiliki tipe bilangan bulat bertanda memiliki peringkat lebih besar atau sama dengan pangkat dari jenis operan lain, maka operan dengan tipe bilangan bulat bertanda dikonversi ke jenis operan dengan jenis bilangan bulat bertanda.
- Jika tidak, jika jenis operan dengan tipe integer yang ditandatangani dapat mewakili semua nilai dari tipe operan dengan tipe integer yang tidak ditandatangani, maka operand dengan tipe integer yang tidak ditandatangani dikonversi ke jenis operan dengan tipe integer yang ditandatangani.
- Jika tidak, kedua operan dikonversikan ke tipe integer yang tidak ditandatangani yang sesuai dengan tipe operan dengan tipe integer yang ditandatangani.
Dalam kasus Anda, kami memiliki satu unsigned int ( u
) dan int int ( i
). Mengacu pada (3) di atas, karena kedua operan memiliki peringkat yang sama, Anda i
harus dikonversi ke integer yang tidak ditandatangani.
6.3.1.3 Bilangan bulat yang ditandatangani dan tidak ditandatangani
- Ketika nilai dengan tipe integer dikonversi ke tipe integer lain selain _Bool, jika nilainya dapat diwakili oleh tipe baru, itu tidak berubah.
- Jika tidak, jika tipe baru tidak ditandatangani, nilainya dikonversi dengan berulang kali menambahkan atau mengurangi satu lebih dari nilai maksimum yang dapat direpresentasikan dalam tipe baru hingga nilainya berada dalam kisaran tipe baru.
- Jika tidak, tipe baru ditandatangani dan nilainya tidak dapat diwakili di dalamnya; baik hasilnya adalah implementasi yang ditentukan atau sinyal yang ditentukan oleh implementasi dinaikkan.
Sekarang kita perlu merujuk ke (2) di atas. Anda i
akan dikonversi ke nilai yang tidak ditandatangani dengan menambahkan UINT_MAX + 1
. Jadi hasilnya akan tergantung pada bagaimana UINT_MAX
didefinisikan pada implementasi Anda. Itu akan besar, tetapi tidak akan meluap, karena:
6.2.5 (9)
Suatu perhitungan yang melibatkan operan yang tidak ditandatangani tidak pernah dapat meluap, karena hasil yang tidak dapat diwakili oleh tipe integer yang tidak ditandatangani berkurang modulo angka yang satu lebih besar dari nilai terbesar yang dapat diwakili oleh tipe yang dihasilkan.
Bonus: Semi-WTF Konversi Aritmatika
#include <stdio.h>
int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;
if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");
return 0;
}
Anda dapat menggunakan tautan ini untuk mencoba ini secara online: https://repl.it/repls/QuickWhimsicalBytes
Bonus: Efek Samping Konversi Aritmatika
Aturan konversi aritmatika dapat digunakan untuk mendapatkan nilai UINT_MAX
dengan menginisialisasi nilai yang tidak ditandatangani -1
, yaitu:
unsigned int umax = -1; // umax set to UINT_MAX
Ini dijamin portabel terlepas dari representasi nomor yang ditandatangani sistem karena aturan konversi yang dijelaskan di atas. Lihat pertanyaan SO ini untuk informasi lebih lanjut: Apakah aman menggunakan -1 untuk mengatur semua bit menjadi true?
Konversi dari yang ditandatangani ke yang tidak ditandatangani tidak serta merta hanya menyalin atau menafsirkan kembali representasi dari nilai yang ditandatangani. Mengutip standar C (C99 6.3.1.3):
Untuk representasi komplemen keduanya yang hampir universal akhir-akhir ini, aturannya sesuai dengan menafsirkan ulang bit. Tetapi untuk representasi lain (sign-and-magnitude atau komplemen satu), implementasi C masih harus mengatur untuk hasil yang sama, yang berarti bahwa konversi tidak bisa hanya menyalin bit. Misalnya, (tidak ditandatangani) -1 == UINT_MAX, terlepas dari representasi.
Secara umum, konversi dalam C didefinisikan untuk beroperasi pada nilai, bukan pada representasi.
Untuk menjawab pertanyaan awal:
Nilai i dikonversi ke int unsigned, menghasilkan
UINT_MAX + 1 - 5678
. Nilai ini kemudian ditambahkan ke nilai unsigned 1234, menghasilkanUINT_MAX + 1 - 4444
.(Tidak seperti overflow yang tidak ditandai, overflow yang ditandatangani memunculkan perilaku yang tidak terdefinisi. Wraparound biasa terjadi, tetapi tidak dijamin oleh standar C - dan optimisasi kompiler dapat mendatangkan malapetaka pada kode yang membuat asumsi yang tidak beralasan.)
sumber
Mengacu pada Alkitab :
sumber
Ketika satu unsigned dan satu variabel yang ditandatangani ditambahkan (atau operasi biner) keduanya secara implisit dikonversi menjadi unsigned, yang dalam hal ini akan menghasilkan hasil yang sangat besar.
Jadi aman dalam arti bahwa hasilnya mungkin besar dan salah, tetapi tidak akan pernah crash.
sumber
Saat mengonversi dari masuk ke ditandatangani, ada dua kemungkinan. Angka yang awalnya positif tetap (atau ditafsirkan sebagai) nilai yang sama. Angka yang awalnya negatif sekarang akan ditafsirkan sebagai angka positif yang lebih besar.
sumber
Seperti yang telah dijawab sebelumnya, Anda dapat melakukan bolak-balik antara yang ditandatangani dan yang tidak ditandatangani tanpa masalah. Kasus batas untuk bilangan bulat yang ditandatangani adalah -1 (0xFFFFFFFF). Coba tambahkan dan kurangi dari itu dan Anda akan menemukan bahwa Anda dapat membalas dan membuatnya benar.
Namun, jika Anda akan melakukan bolak-balik, saya akan sangat menyarankan penamaan variabel Anda sehingga jelas apa jenisnya, misalnya:
Terlalu mudah untuk teralihkan oleh masalah yang lebih penting dan melupakan variabel mana yang jenisnya jika dinamai tanpa petunjuk. Anda tidak ingin melakukan cast ke unsigned dan kemudian menggunakannya sebagai indeks array.
sumber
saya akan dikonversi ke integer yang tidak ditandatangani.
Aman dalam arti didefinisikan dengan baik ya (lihat https://stackoverflow.com/a/50632/5083516 ).
Aturan ditulis dalam biasanya sulit untuk membaca standar-berbicara tetapi pada dasarnya representasi apa pun yang digunakan dalam bilangan bulat yang ditandatangani bilangan bulat bertanda akan berisi representasi komplemen 2 dari angka.
Penambahan, pengurangan dan penggandaan akan bekerja dengan benar pada angka-angka ini sehingga menghasilkan bilangan bulat tak bertanda yang berisi dua nomor komplemen yang mewakili "hasil nyata".
pembagian dan casting untuk tipe integer besar yang tidak ditandatangani akan memiliki hasil yang terdefinisi dengan baik tetapi hasil tersebut tidak akan menjadi representasi pelengkap 2 dari "hasil nyata".
Sementara konversi dari masuk ke unsigned ditentukan oleh standar, sebaliknya adalah implement-defined baik gcc dan msvc mendefinisikan konversi sedemikian rupa sehingga Anda akan mendapatkan "hasil nyata" ketika mengonversi angka komplemen 2 yang disimpan dalam integer yang tidak ditandatangani kembali ke integer yang ditandatangani menjadi integer yang ditandatangani . Saya berharap Anda hanya akan menemukan perilaku lain pada sistem tidak jelas yang tidak menggunakan komplemen 2's untuk bilangan bulat yang ditandatangani.
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation https://msdn.microsoft.com/en-us/library/0eex498h.aspx
sumber
Kelimpahan Jawaban Mengerikan
Ozgur Ozcitak
Ini sepenuhnya salah.
Mats Fredriksson
Ini juga salah. Int yang tidak ditandatangani dapat dipromosikan ke int jika mereka memiliki presisi yang sama karena bit padding dalam tipe yang tidak ditandatangani.
smh
Salah. Mungkin ya dan mungkin juga tidak.
Salah. Entah itu perilaku yang tidak terdefinisi jika menyebabkan overflow atau nilainya dipertahankan.
Anonim
Salah. Tergantung pada ketepatan int relatif terhadap int unsigned.
Taylor Price
Salah. Mencoba menyimpan nilai di luar rentang bilangan bulat yang ditandatangani menghasilkan perilaku yang tidak terdefinisi.
Sekarang saya akhirnya bisa menjawab pertanyaan itu.
Jika presisi int sama dengan int unsigned, u akan dipromosikan ke int yang ditandatangani dan Anda akan mendapatkan nilai -4444 dari ekspresi (u + i). Sekarang, jika Anda dan saya memiliki nilai-nilai lain, Anda mungkin mendapatkan perilaku overflow dan undefined tetapi dengan angka-angka yang tepat Anda akan mendapatkan -4444 [1] . Nilai ini akan memiliki tipe int. Tetapi Anda mencoba untuk menyimpan nilai itu ke int yang tidak ditandatangani sehingga kemudian akan dilemparkan ke int yang tidak ditandatangani dan nilai yang hasilnya akan berakhir adalah (UINT_MAX + 1) - 4444.
Jika presisi dari unsigned int lebih besar daripada int, int yang ditandatangani akan dipromosikan ke int unsigned yang menghasilkan nilai (UINT_MAX + 1) - 5678 yang akan ditambahkan ke int unsigned 1234 yang lain. Haruskah Anda dan saya memiliki nilai-nilai lain, yang membuat ekspresi berada di luar rentang {0..UINT_MAX} nilai (UINT_MAX + 1) akan ditambahkan atau dikurangi hingga hasilnya TIDAK termasuk dalam rentang {0..UINT_MAX) dan tidak ada perilaku tidak terdefinisi yang akan terjadi .
Apa itu presisi?
Integer memiliki bit padding, bit tanda, dan bit nilai. Bilangan bulat yang tidak ditandai tidak memiliki sedikit tanda. Selanjutnya, unsigned char dijamin tidak memiliki bit padding. Jumlah bit nilai yang dimiliki integer adalah seberapa banyak presisi yang dimilikinya.
[Gotchas]
Ukuran makro dari makro saja tidak dapat digunakan untuk menentukan presisi dari bilangan bulat jika bit bantalan hadir. Dan ukuran byte tidak harus berupa octet (delapan bit) seperti yang didefinisikan oleh C99.
[1] Overflow dapat terjadi pada salah satu dari dua titik. Baik sebelum penambahan (selama promosi) - ketika Anda memiliki int unsigned yang terlalu besar untuk masuk ke dalam int. Overflow juga dapat terjadi setelah penambahan bahkan jika int unsigned berada dalam kisaran int, setelah penambahan hasilnya mungkin masih meluap.
sumber
int
dikonversi menjadiunsigned int
ketika konversi aritmatika yang biasa berlaku.int
atauunsigned int
ke salah satu tipe di mana sesuatu tipeunsigned int
atauint
diharapkan. "Atau sama" ditambahkan dalam TC2 untuk memungkinkan jenis peringkat peringkat yang sama denganint
atauunsigned int
dikonversi ke salah satu dari jenis tersebut. Itu tidak pernah dimaksudkan bahwa promosi yang dijelaskan akan mengkonversi antaraunsigned int
danint
. Penentuan tipe umum antaraunsigned int
danint
masih diatur oleh 6.3.1.8, bahkan setelah TC2.