ความแตกต่างระหว่าง size_t และ int ใน C ++ คืออะไร


173

ในหลายภาษา C ++ ตัวอย่างที่ผมเห็นการใช้งานของประเภทที่ที่ฉันจะได้ใช้ง่ายๆsize_t intความแตกต่างคืออะไรและทำไมจึงsize_tควรดีกว่า


3
สำหรับตัวอย่างจริงที่ไม่สามารถใช้แทนกันได้ให้ดูคำถามที่ฉันถามก่อนหน้านี้: stackoverflow.com/questions/645168/ …
Tyler McHenry

คำตอบ:


153

จากวิกิพีเดียที่เป็นมิตร :

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

ขนาดจริงของ size_t ขึ้นอยู่กับแพลตฟอร์ม ข้อผิดพลาดทั่วไปคือสมมติว่า size_t เป็น int ที่ไม่ได้ลงนามซึ่งสามารถนำไปสู่ข้อผิดพลาดในการเขียนโปรแกรมโดยเฉพาะอย่างยิ่งเมื่อสถาปัตยกรรม 64- บิตกลายเป็นที่แพร่หลายมากขึ้น

ตรวจสอบด้วยเหตุใดจึงยังมีปัญหาเรื่อง size_t


76
แล้ว size_t คืออะไร?
ประสบการณ์ใกล้ตาย

8
@NDEthos มันขึ้นอยู่กับ! ที่นี่ลินุกซ์/usr/include/stdlib.hได้รับคำนิยามจาก/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.hนั้นมันเริ่มต้นlong unsigned intเว้นแต่ไฟล์ส่วนหัวอื่น ๆ พูดอย่างอื่น
David Tonhofer

1
ผมยืนยันsize_t เพื่อ tuncation int เป็นอันตราย นี่อาจเป็นหัวข้อปิด แต่จะเขียนโปรแกรมปะแก้เพียงอย่างเดียวเพื่อแก้ไขข้อผิดพลาดชนิดนั้นเมื่อมันเกิดขึ้นพันครั้งในเคอร์เนลลินุกซ์?
2284570

36

size_t เป็นประเภทที่ใช้ในการแสดงขนาด (ตามชื่อของมันหมายถึง) แพลตฟอร์ม (และอาจมีการนำไปใช้) ขึ้นอยู่กับแพลตฟอร์มและควรใช้เพื่อจุดประสงค์นี้เท่านั้น เห็นได้ชัดว่าเป็นขนาด size_t ไม่ได้ลงนาม ฟังก์ชั่น stdlib จำนวนมากรวมถึง malloc, sizeof และฟังก์ชั่นการทำงานของสตริงต่างๆใช้ size_t เป็นประเภทข้อมูล

int จะถูกลงนามโดยค่าเริ่มต้นและแม้ว่าขนาดของมันจะขึ้นอยู่กับแพลตฟอร์มก็ตามมันจะเป็น 32 บิตคงที่ในเครื่องที่ทันสมัยที่สุด

ในการสรุป: ใช้ size_t เพื่อแสดงขนาดของวัตถุและ int (หรือยาว) ในกรณีอื่น ๆ


12

size_tประเภทถูกกำหนดให้เป็นประเภทหนึ่งได้รับการรับรองของsizeofผู้ประกอบการ ในโลกแห่งความเป็นจริงคุณมักจะเห็นการintกำหนดเป็น 32 บิต (สำหรับความเข้ากันได้ย้อนหลัง) แต่size_tถูกกำหนดเป็น 64 บิต (ดังนั้นคุณสามารถประกาศอาร์เรย์และโครงสร้างที่มีขนาดมากกว่า 4 GiB) บนแพลตฟอร์ม 64 บิต หาก a long intคือ 64- บิตสิ่งนี้เรียกว่าการประชุม LP64 ถ้าlong intเป็น 32 บิต แต่พlong long intอยน์เตอร์เป็น 64 บิตนั่นคือ LLP64 นอกจากนี้คุณยังอาจได้รับการย้อนกลับโปรแกรมที่ใช้คำแนะนำ 64 บิตสำหรับความเร็ว แต่ตัวชี้แบบ 32 บิตเพื่อบันทึกหน่วยความจำ นอกจากนี้ยังintมีการเซ็นชื่อและsize_tไม่ได้ลงนาม

นอกจากนั้นในอดีตจำนวนของแพลตฟอร์มอื่น ๆ intที่มีอยู่มีความกว้างขึ้นหรือสั้นกว่าขนาดของพื้นเมือง ในความเป็นจริงในยุค 70 และต้นยุค 80 นี่เป็นเรื่องธรรมดามากกว่า: คอมพิวเตอร์ 8 บิตที่ได้รับความนิยมทั้งหมดมีการลงทะเบียน 8 บิตและที่อยู่ 16 บิตและการเปลี่ยนระหว่าง 16 และ 32 บิตยังผลิตเครื่องจักรจำนวนมาก มีที่อยู่ที่กว้างกว่าการลงทะเบียน ฉันยังคงเห็นคำถามเกี่ยวกับ Borland Turbo C สำหรับ MS-DOS ที่มีโหมดหน่วยความจำขนาดใหญ่ซึ่งมีที่อยู่ 20 บิตที่เก็บไว้ใน 32 บิตบน CPU 16 บิต (แต่สามารถรองรับชุดคำสั่งแบบ 32 บิตของ 80386); Motorola 68000 มี ALU 16 บิตพร้อมการลงทะเบียนและที่อยู่ 32 บิต มีเมนเฟรมของ IBM พร้อมที่อยู่ 15 บิต 24 บิตหรือ 31 บิต คุณยังคงเห็น ALU และขนาดบัสที่แตกต่างกันในระบบฝังตัว

เมื่อใดก็ตามที่intมีขนาดเล็กกว่าsize_tและคุณพยายามจัดเก็บขนาดหรือออฟเซ็ตของไฟล์หรือวัตถุที่มีขนาดใหญ่มากในunsigned intนั้นมีความเป็นไปได้ที่มันจะล้นและทำให้เกิดข้อผิดพลาด ด้วยความintสามารถในการรับจำนวนลบ ถ้ามีintหรือunsigned intกว้างกว่าโปรแกรมจะทำงานอย่างถูกต้อง แต่หน่วยความจำไม่เพียงพอ

โดยทั่วไปคุณควรใช้ประเภทที่ถูกต้องเพื่อวัตถุประสงค์หากคุณต้องการพกพา ผู้คนจำนวนมากจะแนะนำให้คุณใช้คณิตศาสตร์ที่ลงนามแทนการไม่ได้ลงชื่อ (เพื่อหลีกเลี่ยงข้อบกพร่องที่น่ารังเกียจและบอบบางเช่น1U < -3) เพื่อที่การกำหนดมาตรฐานห้องสมุดptrdiff_tใน<stddef.h>เป็นชนิดลงนามในผลการลบตัวชี้จากผู้อื่น

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


8

เป็นเพราะ size_t สามารถเป็นอย่างอื่นได้นอกจาก int (อาจเป็น struct) แนวคิดก็คือมันแยกงานของมันออกจากประเภทพื้นฐาน


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

9
@unwind: C99: TC3, 7.17 §2
Christoph

1
@danio ทำไมถึงเป็นเช่นนั้นคุณอธิบายได้ไหม
อีแร้งของRüppell

2
ฉันจะไม่เชื่อมโยงกับ cplusplus ถ้าฉันเป็นคุณ! หากคุณไม่สามารถอ้างบทบทร้อยกรองวรรคและบรรทัดแล้วมันเป็นเพียงข่าวลือ! :-)
graham.reeds

1
size_tระบุเป็นประเภทจำนวนเต็มไม่ได้ลงนาม C11 §6.5.3.4 5 "ค่าของผลลัพธ์ของตัวดำเนินการทั้งสอง ( sizeof _Alignof) คือการกำหนดการนำไปใช้และประเภทของมัน (ชนิดจำนวนเต็มที่ไม่ได้ลงนาม) คือsize_t"
chux - Reinstate Monica

-1

คำจำกัดความของSIZE_Tพบได้ที่: https://msdn.microsoft.com/en-us/library/cc441980.aspxและhttps://msdn.microsoft.com/en-us/library/cc230394.aspx

การวางข้อมูลที่ต้องการที่นี่:

SIZE_Tเป็นULONG_PTRจำนวนสูงสุดของไบต์ที่ตัวชี้สามารถชี้

ประเภทนี้มีการประกาศดังนี้:

typedef ULONG_PTR SIZE_T;

A ULONG_PTRเป็นแบบยาวที่ไม่ได้ลงนามที่ใช้สำหรับความแม่นยำของตัวชี้ มันถูกใช้เมื่อชี้ตัวชี้ไปยังชนิดยาวเพื่อดำเนินการทางคณิตศาสตร์ตัวชี้

ประเภทนี้มีการประกาศดังนี้:

typedef unsigned __int3264 ULONG_PTR;

2
SIZE_Tไม่ใช่size_tสิ่งที่ OP ถามเกี่ยวกับ
ikegami

2
นี่เป็นส่วนเสริมของ Microsoft ไม่ใช่ส่วนหนึ่งของภาษามาตรฐาน
Davislor

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