กรณีใดบ้างที่ประเภทข้อมูล 'uint' และ 'short' เหมาะสมกว่ามาตรฐาน int (32)


24

ฉันเข้าใจความแตกต่างของความสามารถและคุณค่าที่พวกเขาสามารถนำเสนอได้ แต่ดูเหมือนว่าผู้คนมักจะใช้Int32โดยไม่คำนึงว่าเหมาะสมหรือไม่ ดูเหมือนว่าจะไม่มีใครเคยใช้รุ่นที่ไม่ได้ลงชื่อ ( uint) แม้ว่าจะใช้เวลานานกว่าจะเหมาะกว่าเพราะอธิบายค่าที่ไม่สามารถลบได้ (อาจเป็นตัวแทนของ ID ของบันทึกฐานข้อมูล) นอกจากนี้ดูเหมือนว่าจะไม่มีใครใช้short/Int16โดยไม่คำนึงถึงความจุที่ต้องการของค่า

อย่างมีเหตุผลมีกรณีที่จะดีกว่าที่จะใช้uintหรือไม่short/Int16และถ้าเป็นเช่นนั้น?


13
ความนิยมไม่ได้เป็นตัวชี้วัดที่ใช้การได้สำหรับการประเมินการตัดสินใจออกแบบซอฟต์แวร์ เพียงเพราะการฝึกฝนเป็นที่นิยมไม่ได้หมายความว่าเป็นการฝึกที่เหมาะสมสำหรับแอปพลิเคชันของคุณโดยเฉพาะหรือเป็นการฝึกหัดที่ดี
Robert Harvey


1
ฉันคิดว่าคำตอบสั้น ๆ คือโปรแกรมเมอร์นั้นคุ้นเคยกับซีแมนทิกส์ที่เซ็นชื่อแล้วและมีแนวโน้มที่จะคิดสิ่งเหล่านั้นแม้ว่าจะเกี่ยวข้องกับประเภทที่ไม่ได้ลงนามแล้วก็ตาม คนส่วนใหญ่คิดว่าเป็นเรื่องของโปรแกรมเมอร์ที่ขี้เกียจหรือไม่ได้รับการศึกษา แต่ในความเป็นจริงแล้วโปรแกรมเมอร์ที่มีปัญหาอาจได้รับการศึกษาและระมัดระวังอย่างมากและต้องการหลีกเลี่ยงข้อผิดพลาดที่ละเอียดอ่อน ถ้าคุณต้องการจะดูที่soundsoftware.ac.uk/c-pitfall-unsignedและanteru.net/2010/05/17/736
Theodoros Chatzigiannakis

ในหมายเลขที่ไม่ได้ลงชื่อเครื่องหมายnullมากกว่าทั้งบวกหรือลบ หากคุณคิดว่ามันเป็นสิ่งที่ไม่สามารถลบได้หรือเป็นแง่บวกอยู่เสมอคุณจะต้องประหลาดใจ (และมักจะโกรธ) ที่ผลลัพธ์เพราะมันไม่ได้ผลเช่นนั้นโดยเฉพาะอย่างยิ่งเมื่อเทียบกับหรือลบออก / จากค่าที่ลงชื่อ
Adam D. Ruppe

1
จากประสบการณ์ของฉันโปรแกรมเมอร์จำนวนมากที่เคยเขียนโปรแกรมด้วยภาษา C มักจะสนใจเกี่ยวกับไบต์ที่ยังคงอยู่ในหน่วยความจำ GB และพื้นที่เก็บข้อมูลในวันนี้
user1451111

คำตอบ:


25

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

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

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

  • หากคุณกำลังพยายามแสดงบางสิ่งที่ไม่น่าจะเป็นเชิงลบ ( public uint NumberOfPeople) ให้ใช้ประเภทที่ไม่ได้ลงชื่อ
  • หากคุณกำลังพยายามแสดงบางสิ่งที่ไม่อาจเกิน 255 ( public byte DamagedToothCount) ได้อย่างมีเหตุผลให้ใช้ไบต์
  • หากคุณกำลังพยายามแสดงบางสิ่งที่อาจมีค่ามากกว่า 255 แต่ไม่ควรใช้จำนวนหลักพันให้ใช้ตัวย่อ ( public short JimmyHoffasBankBalance)
  • หากคุณกำลังพยายามที่จะเป็นตัวแทนของบางสิ่งที่อาจเป็นหลายแสนหลายพันล้านแม้กระทั่ง แต่ไม่น่าจะถึงหลายพันล้านครั้งให้ใช้ int ( public int HoursSinceUnixEpoch)
  • หากคุณทราบหมายเลขนี้อย่างแน่นอนอาจมีมูลค่าสูงมากหรือคุณคิดว่ามันอาจมีหลายพันล้าน แต่คุณไม่แน่ใจว่ามีจำนวนหลายพันล้านรายการนานที่สุดคือทางออกที่ดีที่สุดของคุณ ถ้ายาวไม่ใหญ่พอคุณมีปัญหาที่น่าสนใจและต้องเริ่มมองหาตัวเลขที่มีความแม่นยำตามอำเภอใจ ( public long MyReallyGreatAppsUserCountThisIsNotWishfulThinkingAtAll)

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


11
+1 แม้ว่าฉันต้องทำให้ชัดเจนว่า "ตัวเลข" ของโทรศัพท์ไม่ใช่ตัวเลข แต่เป็นสตริงของตัวเลขและการจัดรูปแบบเป็นทางเลือก คุณดูเหมือนจะตระหนักถึงเรื่องนี้ แต่เราไม่ต้องการที่จะเป็นตัวอย่างที่ดีตอนนี้เรา? นอกจากนี้การจำกัด ช่วงของค่าบางอย่างโดยพลการนั้นก็คือ Antipattern ที่มีสายตาสั้น - intทุกที่ยกเว้นว่าคุณทราบความจริงที่ว่าโดเมนปัญหานั้น จำกัด ค่าจริง ๆ - ธนาคารไม่ต้องการบัญชีที่ จำกัด อย่างหนักถึง 33K quid (และคิดว่าสนุก เมื่อนั้นจะล้น…!)
amon

3
เป้าหมายชีวิตใหม่: ร่างสูงเกินขนาดที่ต่ำกว่าประเภทของบัญชีธนาคารของฉัน
recursion.ninja

11
มีเหตุผลที่ดีที่จะไม่ใช้ประเภทที่ไม่ได้ลงชื่อในบางสถานที่ตัวอย่างเช่นเมื่อมีการคำนวณทางคณิตศาสตร์ผสมระหว่างที่ลงชื่อและไม่ได้ลงนาม ดูแนวทางปฏิบัติที่ดีที่สุดเกี่ยวกับ ints ที่ไม่ได้ลงชื่อคืออะไร .

19
ฉันไม่เห็นด้วยกับเหตุผลที่นี่ ประเภทที่ไม่ได้ลงนามมักจะเป็นข้อผิดพลาดเนื่องจากการลบและการเปรียบเทียบนั้นไม่คาดคิดหากคุณคุ้นเคยกับ ints (มันทำงานในลักษณะที่สอดคล้องกัน แต่มันก็ไม่ได้ "เป็นบวกเสมอ") ฉันจะหลีกเลี่ยงพวกเขาจนกว่าคุณจะมีเหตุผลเฉพาะเจาะจงที่จะใช้ ทำไมขนาดถึงสำคัญสำหรับ byte กับ short vs int คุณมักจะไม่ได้ประหยัดพื้นที่เพราะ structs จะรองสมาชิกหรืออาร์เรย์เหล่านั้นไปยังแนวร่วม ฉันจะใช้ไบต์เฉพาะในกรณีที่ขนาดมีความสำคัญจริง ๆ (ไม่น่าเป็นไปได้โดยเฉพาะอย่างยิ่งกับรหัส C # ที่ฉันเคยเห็น) หรือถ้าคุณต้องการคำสั่งพิเศษที่ 255 สำหรับบางสิ่งบางอย่าง
Adam D. Ruppe

4
"ได้รับประโยชน์เป็นพื้นที่หน่วยความจำและซีพียูเวลา" ... ฉันไม่เห็นใด ๆกรณีที่เล็ก ๆ ประเภทจริงจะประหยัดเวลา CPU การดำเนินงานจำนวนเต็มไม่เคยได้รับเร็วขึ้นกว่าที่พวกเขาอยู่ในเครื่องขนาดประเภทคือเท่าที่ CPU longเป็นห่วงคุณอาจรวมทั้งการใช้งาน แน่นอนว่าการประหยัดหน่วยความจำสามารถประหยัดเวลาโดยอ้อมได้ด้วยการปรับปรุงประสิทธิภาพของแคชไลน์และอื่น ๆ แต่ OTOH ปัญหาการจัดตำแหน่งที่มีประเภทขนาดเล็กอาจทำให้เสียเวลาโดยทางอ้อม
leftaroundabout

16

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

ในสภาพแวดล้อมที่มีข้อ จำกัด ของหน่วยความจำหรือเมื่อต้องรับมือกับวัตถุจำนวนมากก็สามารถใช้ตัวแปรขนาดเล็กที่สุดได้ ตัวอย่างเช่นมีความแตกต่างอย่างมีนัยสำคัญในขนาดสำหรับอาร์เรย์ขององค์ประกอบเป็นล้านintกับshorts

บ่อยครั้งที่ไม่ได้เกิดขึ้นในรหัสจริงด้วยเหตุผลอย่างน้อยหนึ่งอย่างต่อไปนี้:

  • ข้อ จำกัด ของข้อมูลยังไม่เป็นที่ทราบล่วงหน้า
  • มีโอกาสที่ข้อ จำกัด ของข้อมูลไม่แข็งหรือเป็นที่รู้กันว่ามีการเปลี่ยนแปลง
  • มีความหวังในการใช้งานฟังก์ชันอีกครั้งด้วยช่วงข้อมูลที่กว้างขึ้น
  • นักพัฒนาไม่ได้ใช้เวลาคิดผ่านข้อ จำกัด
  • การประหยัดหน่วยความจำนั้นไม่มีนัยสำคัญในการปรับให้เหมาะสมโดยใช้ประเภทตัวแปรที่เล็กกว่า

มีเหตุผลที่เป็นไปได้มากขึ้น แต่เหตุผลเหล่านี้ ใช้เวลานานพอสมควรในการตัดสินใจและใช้ตัวแปรชนิดต่าง ๆ ซึ่งไม่ได้ให้ประโยชน์เพียงพอที่จะพิสูจน์


8

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

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

สำหรับประเภทที่ไม่ได้ลงชื่อเพียงครั้งเดียวที่มีประโยชน์จริง ๆ คือเมื่อทำการแลกเปลี่ยนข้อมูลหรือเมื่อแบ่งย่อยตัวเลขออกเป็นชิ้น ๆ ตัวอย่างเช่นหากเราต้องการทำคณิตศาสตร์ในจำนวนเต็ม 96 บิตมันอาจจะง่ายต่อการคำนวณในกลุ่มของจำนวนเต็ม 32 บิตที่ไม่ได้ลงนามมากกว่ากลุ่มที่เป็นจำนวนเต็ม มิฉะนั้นจะไม่มีสถานการณ์ทั้งหมดที่ช่วงของค่า 32- หรือ 64- บิตที่เซ็นชื่อจะไม่เพียงพอ แต่ขนาดของค่าที่ไม่ได้ลงนามจะเพียงพอ


4

โดยทั่วไปแล้วมันเป็นความคิดที่ดีที่จะใช้ประเภทที่ไม่ได้ลงนามเพราะมันล้นในรูปแบบที่ไม่พึงประสงค์ x = 5-6ทันใดนั้นก็เป็นช่วงเวลาในรหัสของคุณ ในขณะที่ประโยชน์ของประเภทที่ไม่ได้ลงนามนั้นจะเพิ่มความแม่นยำเพียงเล็กน้อยและหากบิตนั้นคุ้มกับคุณคุณควรจะใช้ประเภทที่ใหญ่กว่าแทน

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


3
ใน C โอเวอร์โฟลว์ที่ลงนามแล้วยิ่งแย่กว่าโอเวอร์โฟลที่ไม่ได้ลงนาม (เพราะมันเป็นพฤติกรรมที่ไม่ได้กำหนดไว้ในขณะที่ระบุไม่ได้ลงนามเพื่อทำการโอเวอร์โฟลว์เหมือนมาตรวัดระยะทาง) OTOH การลงนามเกิน / อันเดอร์โฟลว์เป็นเรื่องธรรมดาในทางปฏิบัติน้อยกว่าอันเดอร์โฟล์ที่ไม่ได้ลงนาม
Kevin

จริงมากเกินปกติ แต่ที่ลงชื่อจะเห็นได้ชัดเจนและคาดเดาได้มากขึ้น
Jack Aidley

ฉันมักจะเห็น แต่คุณจะต้องตระหนักถึงยกตัวอย่างเช่นว่าคอมไพเลอร์ที่ทันสมัยสามารถเพิ่มประสิทธิภาพi+1>iเข้าไป1ถ้าiมีการลงนามพร้อมกับพื้นที่ทั้งหมดของพฤติกรรมที่น่ารังเกียจอื่น ๆ การโอเวอร์โฟลว์ที่ไม่ได้ลงชื่ออาจทำให้เกิดบั๊กในมุมตัวพิมพ์ ลงนามล้นสามารถทำให้ความหมายของโปรแกรมทั้งหมดของคุณ
Kevin

@ JackAidley ฉันค่อนข้างแน่ใจว่าสิ่งที่คุณพูดไม่สมเหตุสมผลเนื่องจาก 5-6 ให้รูปแบบบิตเดียวกันไม่ว่ามันจะไม่ได้ลงนามหรือไม่ก็ตาม
Ingo

@Ingo: คุณดูรูปแบบบิตบ่อยแค่ไหน? สิ่งที่สำคัญคือความหมายของรูปแบบบิตไม่ใช่สิ่งที่บิตเปิดหรือปิด
Jack Aidley

2

มักจะลืมและอาจสัมผัสกับคำถามของคุณเมื่อจัดการเฉพาะกับประเภท .NET เป็นCLS การปฏิบัติตาม ไม่ใช่ทุกชนิดที่มีในทุกภาษาที่สร้างขึ้นบน. NET Framework

หากคุณกำลังเขียนรหัสที่จะใช้ภาษาอื่นนอกเหนือจาก C # และต้องการให้รหัสนั้นรับประกันว่าจะสามารถทำงานร่วมกับภาษา. NET ได้มากที่สุดเท่าที่จะเป็นไปได้คุณต้อง จำกัด การใช้งานประเภทของคุณให้เป็นมาตรฐาน CLS

ตัวอย่างเช่น VB.NET รุ่นแรก (7.0 และ 7.1) ไม่สนับสนุนจำนวนเต็มที่ไม่ได้ลงชื่อ ( UInteger):

http://msdn.microsoft.com/en-us/library/aa903459(v=vs.71).aspx

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

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