Int ที่ลงนามและไม่ได้ลงนามแตกต่างกันอย่างไร
Int ที่ลงนามและไม่ได้ลงนามแตกต่างกันอย่างไร
คำตอบ:
ดังที่คุณทราบint
s จะถูกเก็บไว้ภายในเป็นไบนารี โดยทั่วไปแล้วจะint
มี 32 บิต แต่ในบางสภาพแวดล้อมอาจมี 16 หรือ 64 บิต (หรือแม้กระทั่งตัวเลขที่แตกต่างกัน แต่โดยปกติแล้วไม่จำเป็นต้องมีกำลังสอง)
แต่สำหรับตัวอย่างนี้ลองดูจำนวนเต็ม 4 บิต เล็ก แต่มีประโยชน์เพื่อวัตถุประสงค์ในการอธิบาย
เนื่องจากมีสี่บิตในจำนวนเต็มจึงสามารถสมมติได้หนึ่งใน 16 ค่า 16 คือสองกำลังสี่หรือ 2 คูณ 2 คูณ 2 คูณ 2 ค่าเหล่านั้นคืออะไร? คำตอบขึ้นอยู่กับว่าจำนวนเต็มนี้เป็น a signed int
หรือunsigned int
. ด้วยunsigned int
ค่าจะไม่เป็นลบ ไม่มีสัญลักษณ์ที่เกี่ยวข้องกับค่านี้ นี่คือ 16 ค่าที่เป็นไปได้ของสี่บิตunsigned int
:
bits value
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 10
1011 11
1100 12
1101 13
1110 14
1111 15
... และนี่คือ 16 ค่าที่เป็นไปได้ของสี่บิตsigned int
:
bits value
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 -8
1001 -7
1010 -6
1011 -5
1100 -4
1101 -3
1110 -2
1111 -1
อย่างที่คุณเห็นสำหรับsigned int
s บิตที่สำคัญที่สุดคือ1
ถ้าจำนวนนั้นเป็นลบ นั่นคือเหตุผลว่าทำไมsigned int
บิตนี้จึงเรียกว่า "บิตเครื่องหมาย"
(unsigned)(-1)
จำเป็นต้องเป็นค่าที่แสดงได้สูงสุดสำหรับunsigned
(ไม่ขึ้นกับการแทนค่าฐานสอง) ซึ่งเป็นจริงเล็กน้อยสำหรับส่วนเสริมของ 2 แต่ไม่ใช่การแสดงอื่น ๆ
int
และunsigned int
เป็นจำนวนเต็มสองประเภทที่แตกต่างกัน ( int
นอกจากนี้ยังสามารถเรียกว่าsigned int
หรือเพียงแค่signed
; unsigned int
นอกจากนี้ยังสามารถเรียกว่าunsigned
.)
ตามที่ระบุชื่อint
เป็นประเภทจำนวนเต็มลงนามและunsigned int
เป็นประเภทจำนวนเต็มที่ไม่ได้ลงชื่อ นั่นหมายความว่าint
สามารถแทนค่าเชิงลบและunsigned int
แสดงได้เฉพาะค่าที่ไม่ใช่ค่าลบเท่านั้น
ภาษา C กำหนดข้อกำหนดบางประการเกี่ยวกับช่วงของประเภทเหล่านี้ ช่วงของint
ต้องมีอย่างน้อย-32767
.. +32767
และช่วงของการunsigned int
ต้องมีอย่างน้อย..0
65535
หมายความว่าทั้งสองประเภทต้องมีอย่างน้อย 16 บิต เป็น 32 บิตในหลายระบบหรือแม้แต่ 64 บิตในบางระบบ int
โดยทั่วไปจะมีค่าติดลบพิเศษเนื่องจากการแทนค่าสองส่วนที่ใช้โดยระบบที่ทันสมัย
บางทีความแตกต่างที่สำคัญที่สุดคือพฤติกรรมของการลงนามเทียบกับเลขคณิตที่ไม่ได้ลงนาม สำหรับการลงนามint
overflow มีพฤติกรรมที่ไม่ได้กำหนดไว้ เพราะunsigned int
ไม่มีน้ำล้น ดำเนินการใด ๆ UINT_MAX + 1U == 0U
ที่ทำให้ค่านอกช่วงของการตัดประเภทรอบดังนั้นสำหรับตัวอย่างเช่น
ประเภทจำนวนเต็มใด ๆ ทั้งที่ลงชื่อหรือไม่ได้ลงนามจะจำลองช่วงย่อยของชุดจำนวนเต็มทางคณิตศาสตร์ที่ไม่สิ้นสุด ตราบใดที่คุณทำงานกับค่าที่อยู่ในช่วงของประเภททุกอย่างก็ใช้ได้ เมื่อคุณเข้าใกล้ขอบเขตล่างหรือบนของประเภทคุณจะพบกับความไม่ต่อเนื่องและคุณจะได้รับผลลัพธ์ที่ไม่คาดคิด สำหรับการลงนามจำนวนเต็มประเภทปัญหาที่เกิดขึ้นเฉพาะสำหรับลบและบวกค่าขนาดใหญ่มากเกินและINT_MIN
INT_MAX
สำหรับประเภทจำนวนเต็มไม่ได้ลงนามปัญหาเกิดขึ้นสำหรับค่าบวกขนาดใหญ่มากและที่ศูนย์ นี่อาจเป็นที่มาของข้อบกพร่อง ตัวอย่างเช่นนี่คือการวนซ้ำที่ไม่มีที่สิ้นสุด:
for (unsigned int i = 10; i >= 0; i --) [
printf("%u\n", i);
}
เพราะi
เป็นเสมอมากกว่าหรือเท่ากับศูนย์; นั่นเป็นลักษณะของประเภทที่ไม่ได้ลงนาม (ภายในลูปเมื่อi
เป็นศูนย์ให้i--
ตั้งค่าเป็นUINT_MAX
)
ในแง่ของคนธรรมดา int ที่ไม่ได้ลงนามคือจำนวนเต็มที่ไม่สามารถเป็นลบได้จึงมีช่วงค่าบวกที่สูงกว่าที่สามารถสันนิษฐานได้ int ที่ลงนามเป็นจำนวนเต็มที่สามารถเป็นลบได้ แต่มีช่วงบวกที่ต่ำกว่าเพื่อแลกกับค่าที่เป็นลบมากขึ้นซึ่งสามารถสันนิษฐานได้
บางครั้งเรารู้ล่วงหน้าว่าค่าที่เก็บไว้ในตัวแปรจำนวนเต็มจะเป็นค่าบวกเสมอเมื่อมีการใช้เพื่อนับเฉพาะสิ่งต่างๆเช่น ในกรณีเช่นนี้เราสามารถประกาศให้ตัวแปรไม่ได้ลงนามเช่นเดียวกับในunsigned int num student;
. ด้วยการประกาศดังกล่าวช่วงของค่าจำนวนเต็มที่อนุญาต (สำหรับคอมไพเลอร์ 32 บิต) จะเปลี่ยนจากช่วง -2147483648 เป็น +2147483647 เป็นช่วง 0 ถึง 4294967295 ดังนั้นการประกาศจำนวนเต็มที่ไม่ได้ลงนามเกือบสองเท่าของขนาดที่ใหญ่ที่สุดที่เป็นไปได้ มูลค่าที่สามารถถือได้
ในทางปฏิบัติมีความแตกต่างสองประการ:
cout
ใน C ++ หรือprintf
ใน C): การแทนค่าบิตจำนวนเต็มที่ไม่ได้ลงนามจะถูกตีความว่าเป็นจำนวนเต็มที่ไม่เป็นลบโดยฟังก์ชันการพิมพ์รหัสนี้สามารถระบุจำนวนเต็มโดยใช้เกณฑ์การสั่งซื้อ:
char a = 0;
a--;
if (0 < a)
printf("unsigned");
else
printf("signed");