Int ที่ลงนามและไม่ได้ลงนามแตกต่างกันอย่างไร
Int ที่ลงนามและไม่ได้ลงนามแตกต่างกันอย่างไร
คำตอบ:
ดังที่คุณทราบints จะถูกเก็บไว้ภายในเป็นไบนารี โดยทั่วไปแล้วจะ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 ints บิตที่สำคัญที่สุดคือ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โดยทั่วไปจะมีค่าติดลบพิเศษเนื่องจากการแทนค่าสองส่วนที่ใช้โดยระบบที่ทันสมัย
บางทีความแตกต่างที่สำคัญที่สุดคือพฤติกรรมของการลงนามเทียบกับเลขคณิตที่ไม่ได้ลงนาม สำหรับการลงนามintoverflow มีพฤติกรรมที่ไม่ได้กำหนดไว้ เพราะ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");