เซ็นชื่อกับจำนวนเต็มที่ไม่ได้ลงนาม


395

ฉันถูกต้องหรือไม่ที่จะพูดถึงความแตกต่างระหว่างจำนวนเต็มที่ลงชื่อและไม่ได้ลงชื่อคือ:

  1. ไม่ได้ลงนามสามารถถือเป็นค่าบวกที่ใหญ่กว่าและไม่มีค่าลบ
  2. Unsigned ใช้บิตนำหน้าเป็นส่วนหนึ่งของค่าในขณะที่เวอร์ชันที่เซ็นชื่อใช้บิตซ้ายสุดเพื่อระบุว่าหมายเลขเป็นบวกหรือลบ
  3. จำนวนเต็มที่ลงนามแล้วสามารถถือได้ทั้งตัวเลขบวกและลบ

ความแตกต่างอื่น ๆ


6
เนื่องจาก0 ไม่ใช่ทั้งบวกและลบจึงเหมาะสมที่จะใช้คำว่าไม่ใช่ค่าลบแทนค่าบวกสำหรับจำนวนเต็มที่ไม่ได้ลงนาม
Daniel

คำตอบ:


344

ไม่ได้ลงนามสามารถถือเป็นค่าบวกที่ใหญ่กว่าและไม่มีค่าลบ

ใช่.

Unsigned ใช้บิตนำหน้าเป็นส่วนหนึ่งของค่าในขณะที่เวอร์ชันที่เซ็นชื่อใช้บิตซ้ายสุดเพื่อระบุว่าหมายเลขเป็นบวกหรือลบ

มีวิธีที่แตกต่างกันในการแสดงจำนวนเต็มที่ลงนาม วิธีที่ง่ายที่สุดในการมองเห็นภาพคือการใช้บิตซ้ายสุดเป็นธง ( เครื่องหมายและขนาด ) แต่สิ่งที่พบได้บ่อยกว่าคือส่วนประกอบสองอย่าง ทั้งสองมีการใช้งานในไมโครโปรเซสเซอร์ที่ทันสมัยที่สุด - จุดลอยใช้เครื่องหมายและขนาดในขณะที่เลขจำนวนเต็มใช้ส่วนประกอบสองอย่าง

จำนวนเต็มที่ลงนามแล้วสามารถถือได้ทั้งตัวเลขบวกและลบ

ใช่


ฉันไม่แน่ใจว่านี่เป็นข้อความนั้น แต่ฉันพบลิงค์อื่น ไปที่หน้า 9 ของ PDF (จริง ๆ แล้วเป็นหน้า 38 ของหนังสือ) และคุณสามารถดูส่วนที่เรียกว่าการแทนข้อมูล (ส่วนที่ 1.3) มันมีคำอธิบายของทุกสิ่งที่กล่าวข้างต้น lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/…
WeirdElfB0y

92

ฉันจะพูดถึงความแตกต่างในระดับฮาร์ดแวร์บน x86 สิ่งนี้ส่วนใหญ่ไม่เกี่ยวข้องยกเว้นว่าคุณกำลังเขียนคอมไพเลอร์หรือใช้ภาษาแอสเซมบลี แต่มันก็ดีที่จะรู้

ประการแรก x86 มีพื้นเมืองสนับสนุนสำหรับส่วนประกอบที่สองของการเป็นตัวแทนของตัวเลขลงนาม คุณสามารถใช้การรับรองอื่น ๆ ได้ แต่จะต้องมีคำแนะนำเพิ่มเติมและโดยทั่วไปจะเป็นการเสียเวลาของตัวประมวลผล

"การสนับสนุนดั้งเดิม" หมายความว่าอะไร โดยทั่วไปฉันหมายถึงมีชุดคำสั่งที่คุณใช้สำหรับหมายเลขที่ไม่ได้ลงชื่อและชุดอื่นที่คุณใช้สำหรับหมายเลขที่เซ็นชื่อ หมายเลขที่ไม่ได้ลงชื่อสามารถอยู่ในทะเบียนเดียวกันกับหมายเลขที่เซ็นชื่อและแน่นอนว่าคุณสามารถผสมคำแนะนำที่ลงชื่อและไม่ได้ลงชื่อโดยไม่ต้องกังวลกับโปรเซสเซอร์ มันขึ้นอยู่กับคอมไพเลอร์ (หรือแอสเซมบลีโปรแกรมเมอร์) เพื่อติดตามว่ามีการลงชื่อหมายเลขหรือไม่และใช้คำแนะนำที่เหมาะสม

ประการแรกตัวเลขเสริมของทั้งสองมีคุณสมบัติที่การบวกและการลบนั้นเหมือนกับตัวเลขที่ไม่ได้ลงนาม มันทำให้ไม่แตกต่างกันว่าตัวเลขเป็นบวกหรือลบ (ดังนั้นคุณเพียงแค่ไปข้างหน้าและADDและSUBหมายเลขของคุณโดยไม่ต้องกังวล.)

ความแตกต่างเริ่มแสดงเมื่อมันมาถึงการเปรียบเทียบ x86 มีวิธีง่าย ๆ ในการแยกความแตกต่าง: ด้านบน / ด้านล่างแสดงถึงการเปรียบเทียบที่ไม่ได้ลงชื่อและมากกว่า / น้อยกว่าบ่งชี้การเปรียบเทียบที่ลงชื่อ (เช่นJAEหมายถึง "กระโดดถ้าสูงกว่าหรือเท่ากับ" และไม่ได้ลงชื่อ)

นอกจากนี้ยังมีชุดคำสั่งการคูณและการหารสองชุดเพื่อจัดการกับจำนวนเต็มที่ลงชื่อและไม่ได้ลงชื่อ

สุดท้าย: หากคุณต้องการตรวจสอบพูดล้นคุณจะทำมันแตกต่างกันสำหรับการลงนามและหมายเลขที่ไม่ได้ลงนาม


คุณหมายถึงอะไรโดยหมายเลขที่ไม่ได้ลงนามและที่ลงนามสิ่งที่ฉันต้องการถามคือถ้าฉันเขียน int a = 2 และลงนาม int b = 2 ดังนั้นพวกเขาทั้งสองลงชื่อหรือไม่ได้ลงชื่อหมายเลขที่ลงนามหรือไม่ได้ขึ้นอยู่กับประเภท เรากำหนดให้หรือขึ้นอยู่กับว่ามันมีสัญญาณเชิงลบหรือไม่? สิ่งนี้ได้ดักฟังฉันมาระยะหนึ่งแล้ว
Suraj Jain

@SurajJain ลงนามและไม่ได้รับการอ้างอิงถึงประเภท พวกเขาบ่งชี้ว่ามันเป็นไปได้สำหรับตัวแปรหรือการแสดงออกที่จะมีค่าลบ
Artelius

ฉันมีข้อสงสัยดังต่อไปนี้ฉันได้ถามคำถามยังไม่มีคำตอบที่น่าพอใจลองดูที่นี่stackoverflow.com/questions/41399092/…
Suraj Jain

62

เขาเพียงถามเกี่ยวกับการลงนามและไม่ได้ลงนาม ไม่ทราบว่าทำไมผู้คนจึงเพิ่มสิ่งพิเศษลงในสิ่งนี้ ให้ฉันบอกคำตอบ

  1. ไม่ได้ลงนาม: ประกอบด้วยเฉพาะค่าที่ไม่เป็นลบเช่น 0 ถึง 255

  2. ลงนาม: ประกอบด้วยทั้งค่าลบและค่าบวก แต่ในรูปแบบที่แตกต่างกันเช่น

    • 0 ถึง +127
    • -1 ถึง -128

และคำอธิบายนี้เป็นเรื่องเกี่ยวกับระบบตัวเลข 8 บิต


17

เพียงไม่กี่จุดเพื่อความสมบูรณ์:

  • คำตอบนี้พูดถึงการเป็นตัวแทนจำนวนเต็มเท่านั้น อาจมีคำตอบอื่นสำหรับจุดลอยตัว

  • การแสดงจำนวนลบอาจแตกต่างกันไป ที่พบมากที่สุด (โดยไกล - มันเกือบเป็นสากลในปัจจุบัน) ที่ใช้งานในวันนี้คือส่วนประกอบสองอย่าง การเป็นตัวแทนอื่น ๆ รวมถึงส่วนเสริม (ค่อนข้างหายาก) และขนาดที่เซ็นชื่อ (หายไปยาก - อาจใช้กับชิ้นส่วนของพิพิธภัณฑ์เท่านั้น) ซึ่งใช้บิตสูงเป็นตัวบ่งชี้สัญญาณที่มีบิตที่เหลืออยู่แทนค่าสัมบูรณ์ของตัวเลข

  • เมื่อใช้ส่วนเติมเต็มของสองตัวแปรสามารถแสดงช่วงที่ใหญ่กว่า (โดยหนึ่ง) ของจำนวนลบมากกว่าจำนวนบวก นี่เป็นเพราะศูนย์รวมอยู่ในตัวเลข 'บวก' (เนื่องจากบิตเครื่องหมายไม่ได้ถูกตั้งค่าเป็นศูนย์) แต่ไม่ใช่ตัวเลขลบ นี่หมายความว่าไม่สามารถแสดงค่าสัมบูรณ์ของจำนวนลบที่น้อยที่สุดได้

  • เมื่อใช้ส่วนประกอบที่สมบูรณ์หรือขนาดที่เซ็นชื่อคุณสามารถมีจำนวนศูนย์ที่แสดงว่าเป็นจำนวนบวกหรือลบ (ซึ่งเป็นหนึ่งในสองสามเหตุผลที่การรับรองเหล่านี้ไม่ได้ใช้)


ถ้าฉันเขียน int ที่ไม่ได้ลงนาม a = -2 และลงนาม int b = -2 การแทนพื้นฐานจะเหมือนกันฉันรู้ว่ามันไม่ดีที่จะมีจำนวนที่ไม่ได้ลงนามซึ่งให้ค่าลบ แต่ยังถ้าฉันให้มันสิ่งที่จะเป็น ตัวแทนพื้นฐาน?
Suraj Jain

1
ไมเนอร์ niggle: ใช้สัญญาณและขนาดในจุดลอยตัว IEEE ดังนั้นจริงๆแล้วมันค่อนข้างธรรมดา :-)
alastair

14

ตามสิ่งที่เราเรียนรู้ในชั้นเรียนจำนวนเต็มที่ลงนามสามารถแสดงทั้งจำนวนบวกและลบในขณะที่จำนวนเต็มไม่ได้ลงนามเป็นเพียงไม่ลบ

ตัวอย่างเช่นการดูตัวเลข8 บิต :

ค่าที่ไม่ได้ลงนาม0ถึง255

ช่วงของค่าที่มีการลงชื่อตั้งแต่-128ถึง127


11

ทุกอย่างยกเว้นจุด 2 ถูกต้อง มีสัญกรณ์ที่แตกต่างกันมากมายสำหรับ int ที่ลงนามแล้วการใช้งานบางอย่างใช้ครั้งแรกส่วนอื่น ๆ ใช้สุดท้ายและอื่น ๆ ใช้สิ่งที่แตกต่างกันโดยสิ้นเชิง ทุกอย่างขึ้นอยู่กับแพลตฟอร์มที่คุณทำงานด้วย


นั่นเป็นสิ่งเล็ก ๆ น้อย ๆ และสิ่งใหญ่โต?
vIceBerg

น้อยกับใหญ่ endian เกี่ยวข้องกับลำดับของไบต์บนแพลตฟอร์ม endian น้อยอาจทำ 0xFF 0xFE 0x7F ในขณะที่ endian ใหญ่จะทำ 0x7F 0xFE 0xFF
Jasper Bekkers

10

ข้อแตกต่างอีกอย่างคือเมื่อคุณแปลงระหว่างจำนวนเต็มที่มีขนาดต่างกัน

ตัวอย่างเช่นถ้าคุณกำลังแยกจำนวนเต็มจากกระแสข้อมูลไบต์ (พูด 16 บิตเพื่อความง่าย) โดยมีค่าที่ไม่ได้ลงนามคุณสามารถทำได้:

i = ((int) b[j]) << 8 | b[j+1]

(อาจจะโยน 2 ครั้งไบต์ แต่ฉันคาดเดาคอมไพเลอร์จะทำสิ่งที่ถูกต้อง)

ด้วยค่าที่ลงนามคุณจะต้องกังวลเกี่ยวกับส่วนขยายสัญญาณและทำ:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF

5

พูดโดยทั่วไปว่าถูกต้อง โดยที่ไม่รู้อะไรเพิ่มเติมเกี่ยวกับสาเหตุที่คุณมองหาความแตกต่างฉันไม่สามารถนึกถึงความแตกต่างอื่น ๆ ระหว่างการเซ็นชื่อและไม่ได้ลงชื่อ


4

เหนือสิ่งที่คนอื่นพูดใน C คุณจะไม่สามารถล้นจำนวนเต็มที่ไม่ได้ลงนาม พฤติกรรมที่ถูกกำหนดให้เป็นโมดูลัสเลขคณิต คุณสามารถล้นจำนวนเต็มที่ลงนามและในทางทฤษฎี (แม้ว่าจะไม่ใช่ในทางปฏิบัติในระบบกระแสหลักในปัจจุบัน) การล้นอาจทำให้เกิดข้อผิดพลาด (อาจคล้ายกับหารด้วยศูนย์ความผิด)


1
โปรดทราบว่าโอเวอร์โฟลว์จำนวนเต็มที่ลงนามแล้วจะเรียกใช้พฤติกรรมที่ไม่ได้กำหนดและคอมไพเลอร์สมัยใหม่มีความก้าวร้าวมากในการหาจุดนี้และใช้ประโยชน์เพื่อแก้ไขโปรแกรมของคุณในแบบที่ไม่คาดคิด นี่เป็นปัญหามากกว่าตอนนี้เมื่อ 7 ปีที่แล้ว
Jonathan Leffler

4
  1. ใช่จำนวนเต็มไม่ได้ลงนามสามารถเก็บค่าขนาดใหญ่
  2. ไม่มีวิธีต่าง ๆ ในการแสดงค่าบวกและลบ
  3. ใช่จำนวนเต็มที่ลงนามสามารถมีได้ทั้งค่าบวกและค่าลบ

4

(เพื่อตอบคำถามที่สอง) เพียงใช้บิตสัญญาณเท่านั้น (และไม่ใช่ส่วนเติมเต็ม 2) คุณสามารถจบด้วย -0 ไม่สวยมาก


เพียงเพิ่มคำตอบนี้โดยทั่วไปหมายความว่า 10 == 00 โดยที่ตัวเลขทั้งสองเป็นฐาน 2

4

เลขจำนวนเต็มที่ลงนามใน C แทนตัวเลข หากaและbเป็นตัวแปรของประเภทจำนวนเต็มที่ลงนามมาตรฐานจะไม่ต้องการให้คอมไพเลอร์สร้างที่a+=bเก็บนิพจน์เป็นaสิ่งอื่นใดนอกจากผลรวมเลขคณิตของค่าที่เกี่ยวข้อง เพื่อให้แน่ใจว่าหากผลรวมเลขคณิตไม่พอดีaตัวประมวลผลอาจไม่สามารถใส่ได้ แต่มาตรฐานจะไม่ต้องการให้คอมไพเลอร์ตัดทอนหรือตัดค่าหรือทำสิ่งอื่นสำหรับเรื่องนั้นถ้าค่าที่เกิน ข้อ จำกัด สำหรับประเภทของพวกเขา โปรดทราบว่าแม้ว่ามาตรฐานไม่จำเป็นต้องมีการใช้งาน C จะได้รับอนุญาตให้ดักจับทางคณิตศาสตร์ล้นด้วยค่าที่ลงนามแล้ว

จำนวนเต็มที่ไม่ได้ลงนามใน C ทำหน้าที่เป็นวงแหวนพีชคณิตนามธรรมของจำนวนเต็มซึ่งสอดคล้องกันแบบโมดูโลกำลังสองบางส่วนยกเว้นในสถานการณ์ที่เกี่ยวข้องกับการแปลงหรือการดำเนินการด้วยประเภทที่มีขนาดใหญ่กว่า การแปลงจำนวนเต็มขนาดใด ๆเป็นชนิดที่ไม่ได้ลงนามแบบ 32 บิตจะทำให้สมาชิกที่สอดคล้องกับสิ่งต่าง ๆ ที่สอดคล้องกับจำนวนเต็ม mod 4,294,967,296 เหตุผลที่ลบ 3 จาก 2 ให้ผล 4,294,967,295 คือการเพิ่มบางอย่างที่สอดคล้องกันกับ 3 เข้ากับบางอย่างที่สอดคล้องกันกับ 4,294,967,295 จะให้บางสิ่งที่สอดคล้องกันกับ 2

แหวนแบบพีชคณิตนามธรรมมักเป็นสิ่งที่มีประโยชน์ แต่น่าเสียดายที่ C ใช้ความเซ็นชื่อเป็นปัจจัยในการตัดสินใจว่าประเภทควรเป็นแหวนหรือไม่ ค่าที่ไม่ได้รับการลงนามจะถือว่าเป็นตัวเลขมากกว่าสมาชิกวงแหวนเมื่อถูกแปลงเป็นประเภทที่มีขนาดใหญ่กว่าและค่าที่ไม่ได้ลงนามนั้นเล็กกว่าintรับการแปลงเป็นตัวเลขเมื่อดำเนินการทางคณิตศาสตร์ใด ๆ ก็ตาม ถ้าvเป็นuint32_tซึ่งเท่ากับ4,294,967,294แล้วควรจะทำv*=v; v=4น่าเสียดายที่ถ้าintเป็น 64 บิตก็ไม่ได้บอกว่าv*=v;จะทำอะไรได้

ให้มาตรฐานเหมือนเดิมฉันขอแนะนำให้ใช้ประเภทที่ไม่ได้ลงนามในสถานการณ์ที่ต้องการพฤติกรรมที่เกี่ยวข้องกับวงแหวนเชิงพีชคณิตและประเภทที่เซ็นชื่อเมื่อต้องการแสดงตัวเลข มันโชคร้ายที่ C ดึงความแตกต่างในแบบที่เคยทำ แต่พวกมันคือสิ่งที่พวกเขาเป็น


3

จำนวนเต็มที่ไม่ได้ลงนามมีแนวโน้มที่จะจับคุณในกับดักเฉพาะมากกว่าที่เป็นจำนวนเต็มที่ลงนามแล้ว กับดักมาจากความจริงที่ว่าในขณะที่ 1 & 3 ข้างต้นนั้นถูกต้องทั้งจำนวนเต็มทั้งสองประเภทสามารถกำหนดค่านอกขอบเขตของสิ่งที่มันสามารถ "ถือ" และมันจะถูกแปลงอย่างเงียบ ๆ

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

เมื่อคุณเรียกใช้งานคุณจะได้รับผลลัพธ์ต่อไปนี้แม้ว่าค่าทั้งสองจะถูกกำหนดเป็น -1 และมีการประกาศต่างกัน

signed < 0
-1 == -1
4294967295d == 4294967295d

0

ข้อแตกต่างที่รับประกันเพียงอย่างเดียวระหว่างค่าที่เซ็นชื่อและค่าที่ไม่ได้ลงชื่อใน C คือค่าที่ลงนามนั้นอาจเป็นค่าลบ, 0 หรือค่าบวกในขณะที่ค่าที่ไม่ได้ลงนามสามารถเป็น 0 หรือค่าบวกเท่านั้น ปัญหาคือ C ไม่ได้กำหนดรูปแบบของประเภท (ดังนั้นคุณไม่ทราบว่าจำนวนเต็มของคุณเป็นส่วนเติมเต็มของสอง) การพูดสองจุดแรกที่คุณพูดอย่างเคร่งครัดนั้นไม่ถูกต้อง


0

คุณต้องใช้ Integers ที่ไม่ได้ลงชื่อเมื่อเขียนโปรแกรมบนระบบฝังตัว ในลูปเมื่อไม่จำเป็นต้องใช้จำนวนเต็มที่มีลายเซ็นการใช้จำนวนเต็มที่ไม่ได้ลงนามจะช่วยให้ปลอดภัยสำหรับการออกแบบระบบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.