ถ่านมีการเซ็นชื่อหรือไม่ได้ลงนามโดยค่าเริ่มต้น?


158

ในหนังสือ "Complete Reference of C" ได้มีการกล่าวไว้ว่า charเป็นค่าเริ่มต้นที่ไม่ได้ลงชื่อ

แต่ฉันพยายามที่จะตรวจสอบกับ GCC และ Visual Studio มันคือการเป็นลงนามโดยค่าเริ่มต้น

อันไหนที่ถูก?


5
หนังสืออ้างอิง C หนึ่งเล่มที่ฉันเชื่อถือคือ "C: A คู่มืออ้างอิง" ของ Harbison & Steele ( careferencemanual.com ) แน่นอนว่ามาตรฐานคือคำสุดท้าย แต่มันไม่สามารถอ่านได้มากและให้ข้อมูลเพียงเล็กน้อยเกี่ยวกับการใช้ก่อนมาตรฐานและทั่วไป (เช่น. POSIX) ที่ใช้ซึ่งอยู่นอกมาตรฐาน Harbison & Steele ค่อนข้างอ่านได้ละเอียดและอาจถูกต้องกว่าแหล่งอ้างอิงส่วนใหญ่ อย่างไรก็ตามมันก็ไม่ใช่การสอนดังนั้นถ้าคุณอยู่ในช่วงเริ่มต้นของการเรียนรู้มันอาจไม่ใช่เรื่องใหญ่ที่จะกระโดดลงไป
Michael Burr

15
ฉันคิดว่าหนังสือที่คุณกำลังอ่านคือC: The Complete Referenceโดย Herbert Schildt จากการทบทวนหนังสือเล่มนี้ ( accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm ): ฉันจะไม่แนะนำหนังสือเล่มนี้ (คุณหลายคนให้น้ำหนักมากเกินไปต่อความคิดเห็นของฉัน) แต่ ฉันไม่คิดว่ามันสมควรได้รับความคลั่งไคล้แบบเดียวกันกับที่ถูกโยนลงไปในงานอื่นของเขา ขณะที่ไมเคิลกล่าวว่าการอ้างอิงที่ดีมากคือฮาร์บิสันและสตีล
Alok Singhal

สองเซ็นต์ของฉันที่นี่: เพราะcharสามารถที่ไม่ได้ลงชื่อเป็นกฎในการใช้นิ้วหัวแม่มือหนึ่งintในการอ่านค่าใช้ซึ่งอาจส่งคืนgetchar() มักจะถูกกำหนดเป็นหรือค่าลบอื่น ๆ ซึ่งจัดเก็บในไม่ใช่สิ่งที่คุณต้องการ นี่คือคำประกาศ: BTW คำแนะนำนี้มาจากหนังสือ "C: A Reference Manual" EOFEOF-1unsignedextern int getchar();
Maxim Chetrusca

6
การอ้างอิง C เดียวที่ฉันเชื่อถือคือ ISO / IEC 9899: 2011 :-)
Jeff

3
@ MaxChetrusca คำแนะนำที่ดี แต่มีเหตุผลที่ไม่ดี: แม้ในcharกรณีที่ลงชื่อคุณต้องใช้intเพื่อเก็บค่าส่งคืน
Antti Haapala

คำตอบ:


204

หนังสือเล่มนี้ผิด มาตรฐานไม่ได้ระบุว่าธรรมดาcharลงชื่อหรือไม่ได้ลงนาม

ในความเป็นจริงมาตรฐานกำหนดสามประเภทที่แตกต่างกันchar, และsigned char unsigned charหากคุณ#include <limits.h>และจากนั้นดูCHAR_MINคุณสามารถค้นหาว่าธรรมดาcharเป็นsignedหรือunsigned(ถ้าCHAR_MINน้อยกว่า 0 หรือเท่ากับ 0) แต่ถึงแม้ว่าทั้งสามชนิดนั้นแตกต่างกันไปตามมาตรฐานที่เกี่ยวข้อง

โปรดทราบว่าcharนี่เป็นวิธีพิเศษ ถ้าคุณประกาศตัวแปรเป็นintมันเป็น 100% signed intเทียบเท่ากับการประกาศเป็น สิ่งนี้เป็นจริงเสมอสำหรับคอมไพเลอร์และสถาปัตยกรรมทั้งหมด


1
@Alok: ไม่เหมือนกันสำหรับบางประเภทข้อมูลอื่น ๆ เช่นintหมายถึงsigned intเสมอใช่มั้ย? นอกเหนือจากcharประเภทข้อมูลอื่น ๆ ที่มีความสับสนเหมือนกันCคืออะไร?
Lazer

8
@eSKay: ใช่charเป็นประเภทเดียวที่สามารถลงนามหรือไม่ได้ลงนาม ตัวอย่างเช่นintเทียบเท่า signed int
Alok Singhal

28
มีเหตุผลทางประวัติศาสตร์อย่างฮิสทีเรีย, เอ่อ, - ในช่วงต้นชีวิตของซี "มาตรฐาน" ถูกพลิกล้มอย่างน้อยสองครั้งและคอมไพเลอร์รุ่นแรก ๆ ที่ได้รับความนิยมบางตัวก็จบลงแบบเดียวและอื่น ๆ
Hot Licks

9
@AlokSinghal: นอกจากนี้ยังมีการใช้งานที่กำหนดไว้ว่าฟิลด์ประเภทบิตintมีการเซ็นชื่อหรือไม่ได้ลงนาม
Keith Thompson

@ KeithThompson ขอบคุณสำหรับการแก้ไข ฉันมักจะลืมรายละเอียดบางอย่างเกี่ยวกับประเภทฟิลด์บิตเนื่องจากฉันไม่ค่อยได้ใช้มากนัก
Alok Singhal

67

ตามที่Alok ชี้ให้เห็นมาตรฐานจะเป็นไปตามการนำไปปฏิบัติ

สำหรับ GCC เริ่มต้นมีการลงนาม -funsigned-charแต่คุณสามารถปรับเปลี่ยนด้วย ทราบ:สำหรับ GCC ใน Android NDK เริ่มต้นคือไม่ได้ลงนาม -fsigned-charนอกจากนี้คุณยังสามารถอย่างชัดเจนขอเซ็นสัญญากับตัวละคร

เมื่อวันที่ MSVC เริ่มต้นมีการลงนาม /Jแต่คุณสามารถปรับเปลี่ยนด้วย


2
น่าสนใจที่คำอธิบายของ Schildt ไม่ตรงกับพฤติกรรมของ MSVC เนื่องจากหนังสือของเขามักจะมุ่งเน้นไปที่ผู้ใช้ MSVC ฉันสงสัยว่า MS เปลี่ยนค่าเริ่มต้นในบางจุดหรือไม่?
Michael Burr

1
ฉันคิดว่ามันไม่ได้ขึ้นอยู่กับคอมไพเลอร์ แต่อยู่บนแพลตฟอร์ม ฉันคิดว่าอักขระที่เหลืออยู่เป็นประเภทที่สามของ "ประเภทข้อมูลอักขระ" เพื่อให้สอดคล้องกับสิ่งที่ระบบในเวลานั้นใช้เป็นอักขระที่พิมพ์ได้
Spidey

10
เอกสาร GCCบอกว่ามันขึ้นอยู่กับเครื่อง: "เครื่องแต่ละชนิดมีค่าเริ่มต้นสำหรับสิ่งที่ถ่านควรเป็นเช่นถ่านที่ไม่ได้ลงนามโดยค่าเริ่มต้นหรือเช่นถ่านที่ลงนามโดยค่าเริ่มต้น "
Deduplicator

1
คุณช่วยกรุณาให้แหล่งที่มาสำหรับบันทึกย่อของคุณว่าใน Android เริ่มต้นเป็นถ่านที่ไม่ได้ลงชื่อ?
phlipsy

1
@Spidey มาตรฐาน C ทำให้ไม่มีความแตกต่างที่แท้จริงระหว่างคอมไพเลอร์แพลตฟอร์มและสถาปัตยกรรมซีพียู มันเพียงรวมเข้าด้วยกันภายใต้ "การใช้งาน"
plugwash

35

C99 N1256 ฉบับร่าง "ประเภท" 6.2.5 / 15 มีสิ่งนี้ที่จะพูดเกี่ยวกับประเภทของการลงนามchar:

การดำเนินการจะต้องกำหนดถ่านให้มีช่วงเหมือนกันการแสดงและพฤติกรรมเช่นเดียวกับถ่านที่ลงนามแล้ว

และในเชิงอรรถ:

CHAR_MINกำหนดไว้ใน<limits.h>จะมีค่าใดค่าหนึ่ง0หรือSCHAR_MINและสามารถใช้เพื่อแยกความแตกต่างของสองตัวเลือก โดยไม่คำนึงถึงทางเลือกที่ทำเป็นcharประเภทแยกต่างหากจากอีกสองคนและเข้ากันไม่ได้กับทั้ง


7

อ้างอิงจากหนังสือภาษา C Programming โดย Dennis Ritchie ซึ่งเป็นหนังสือมาตรฐาน de-facto สำหรับ ANSI C ตัวอักษรธรรมดาที่ลงนามหรือไม่ได้ลงนามนั้นขึ้นอยู่กับเครื่อง


9
ไม่จำเป็นว่าในกรณีที่อักขระที่พิมพ์ได้นั้นเป็นค่าบวกเสมอ มาตรฐาน C รับประกันว่าสมาชิกทั้งหมดของชุดอักขระการดำเนินการพื้นฐานมีค่าที่ไม่เป็นลบ
Keith Thompson

7

ตามมาตรฐาน C การลงนามของถ่านธรรมดาคือ "การใช้งานที่กำหนดไว้"

โดยทั่วไปผู้ใช้งานจะเลือกใช้งานสถาปัตยกรรมที่มีประสิทธิภาพมากกว่า ในระบบ x86 ถ่านมีการลงนามโดยทั่วไป บนระบบแขนมันไม่ได้ลงนามโดยทั่วไป (Apple iOS เป็นข้อยกเว้น)



2
@plugwash คำตอบของคุณอาจจะเป็นเพราะ downvoted ทิมโพสต์หายกุญแจ อย่างจริงจังแม้ว่าคุณไม่ควรกังวลกับ downvote เดียวตราบใดที่คุณแน่ใจว่าคำตอบของคุณถูกต้อง (ซึ่งเป็นในกรณีนี้) มันเกิดขึ้นกับฉันหลายครั้งแล้วที่โพสต์ของฉันถูกโหวตโดยไม่มีเหตุผลที่ถูกต้อง ไม่ต้องกังวลกับมันบางครั้งผู้คนก็ทำสิ่งแปลก ๆ
Donald Duck

1
เหตุใดการลงชื่อใช้งาน char จึงมีประสิทธิภาพมากกว่าใน x86 แหล่งใดบ้าง?
martinkunev

2

ตามที่ "ภาษาการเขียนโปรแกรม C ++" โดย Bjarne Stroustrup charคือ "การใช้งานที่กำหนด" มันอาจจะเป็นsigned charหรือunsigned charขึ้นอยู่กับการดำเนินงาน คุณสามารถตรวจสอบว่ามีการลงนามหรือไม่โดยใช้charstd::numeric_limits<char>::is_signed


9
นี่คือคำถาม C C ++ เป็นภาษาที่แตกต่างกันและการอ้างอิง C ++ นั้นไม่มีความเกี่ยวข้องกับ C.
MM

1

ตอนนี้เรารู้ว่าใบมาตรฐานนั้นขึ้นอยู่กับการใช้งาน

แต่วิธีการตรวจสอบประเภทคือsignedหรือunsignedเช่นchar?

ฉันเขียนมาโครเพื่อทำสิ่งนี้:

#define IS_UNSIGNED(t) ((t)~1 > 0)

และทดสอบด้วยgcc, และclang clแต่ฉันไม่แน่ใจว่ามันปลอดภัยเสมอสำหรับกรณีอื่น ๆ


เกิดอะไรขึ้นกับ CHAR_MIN ปกติ <0 (หรือ WCHAR_MIN <0 สำหรับ wchar_t)
Öö Tiib
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.