size_t ใน C คืออะไร


626

ฉันกำลังสับสนกับsize_tใน C. ฉันรู้ว่ามันจะถูกส่งกลับโดยsizeofผู้ประกอบการ แต่มันคืออะไรกันแน่? เป็นประเภทข้อมูลหรือไม่

สมมติว่าฉันมีforลูป:

for(i = 0; i < some_size; i++)

ฉันควรใช้int i;หรือsize_t i;?


11
หากเป็นเพียงตัวเลือกของคุณให้ใช้intหากsome_sizeลงชื่อsize_tถ้ายังไม่ได้ลงนาม
เนท

8
@ เนทนั่นไม่ถูกต้อง POSIX มีประเภท ssize_t แต่ชนิดที่ถูกต้องจริงในการใช้คือ ptrdiff_t
Steven Stewart-Gallus

2
คำตอบที่ไม่ชัดเจนเช่นเดียวกับในการเขียนโปรแกรมระดับต่ำ: C สภาและการดำเนินการเกี่ยวกับIntel® 64 ตามที่ระบุไว้ในหนังสือเล่มนี้การใช้ดัชนีint iอาจไม่เพียงพอที่จะระบุอาร์เรย์จำนวนมาก ดังนั้นโดยใช้size_t iคุณสามารถระบุดัชนีได้มากขึ้นดังนั้นแม้ว่าคุณจะมีอาร์เรย์จำนวนมากที่ไม่น่าจะมีปัญหาก็ตาม size_tเป็นประเภทข้อมูล: โดยปกติแล้วจะเป็นunsigned long intแต่ขึ้นอยู่กับระบบของคุณ
bruno

คำตอบ:


461

จาก Wikipedia :

ตามมาตรฐาน ISO C 1999 (C99) size_tเป็นประเภทจำนวนเต็มที่ไม่ได้ลงชื่ออย่างน้อย 16 บิต (ดูหัวข้อ 7.17 และ 7.18.3)

size_tเป็นชนิดข้อมูลที่ไม่ได้ลงชื่อกำหนดโดยหลาย C / C ++ มาตรฐานเช่น C99 มาตรฐาน ISO / IEC 9899 stddef.hมาตรฐานที่กำหนดไว้ใน 1ก็สามารถที่จะนำเข้าต่อไปโดยรวมของ เป็นไฟล์นี้ภายในย่อยรวมถึงstdlib.hstddef.h

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

ในฐานะนัยหมายsize_tถึงชนิดที่รับประกันว่าจะเก็บดัชนีอาร์เรย์


4
"ฟังก์ชั่นห้องสมุดที่ใช้หรือคืนขนาดคาดว่าเป็นประเภท ... size_t" ยกเว้นว่า stat () ใช้ off_t สำหรับขนาดของไฟล์
Draemon

64
@Draemon ความคิดเห็นนั้นสะท้อนถึงความสับสนขั้นพื้นฐาน size_tสำหรับวัตถุในหน่วยความจำ มาตรฐาน C ไม่ได้กำหนดstat()หรือoff_t(เป็นคำจำกัดความของ POSIX) หรือสิ่งใดที่เกี่ยวข้องกับดิสก์หรือระบบไฟล์ - มันหยุดตัวเองที่FILEสตรีม การจัดการหน่วยความจำเสมือนแตกต่างอย่างสิ้นเชิงจากระบบไฟล์และการจัดการไฟล์เท่าขนาดที่ต้องการดังนั้นการกล่าวถึงoff_tไม่เกี่ยวข้องที่นี่
jw013

3
@ jw013: ฉันแทบจะไม่เรียกมันว่าเป็นความสับสนขั้นพื้นฐาน แต่คุณสร้างประเด็นที่น่าสนใจ ยังข้อความที่ยกมาไม่ได้พูดว่า "ขนาดของวัตถุในหน่วยความจำ" และ "ชดเชย" แทบจะเป็นชื่อที่ดีสำหรับประเภทขนาดโดยไม่คำนึงว่ามันจะถูกเก็บไว้ที่ไหน
Draemon

30
@Draemon เป็นจุดที่ดี คำตอบนี้เสนอราคา Wikipedia ซึ่งในกรณีนี้ไม่มีคำอธิบายที่ดีที่สุดในความคิดของฉัน มาตรฐาน C นั้นมีความชัดเจนมากขึ้น: เป็นตัวกำหนดsize_tประเภทของผลลัพธ์ของsizeofผู้ปฏิบัติงาน (7.17p2 เกี่ยวกับ<stddef.h>) ส่วนที่ 6.5 อธิบายว่า C นิพจน์ทำงานอย่างไร (6.5.3.4 สำหรับsizeof) เนื่องจากคุณไม่สามารถนำsizeofไปใช้กับไฟล์ดิสก์ (ส่วนใหญ่เป็นเพราะ C ไม่ได้กำหนดวิธีการทำงานของดิสก์และไฟล์) จึงไม่มีที่ว่างสำหรับความสับสน กล่าวโทษ Wikipedia (และคำตอบนี้เพื่ออ้างถึง Wikipedia และไม่ใช่มาตรฐาน C จริง)
jw013

2
@Draemon - ฉันจะเห็นด้วยกับการประเมิน "ความสับสนพื้นฐาน" หากคุณยังไม่ได้อ่านมาตรฐาน C / C ++ คุณอาจคิดว่า "object" หมายถึง "การเขียนโปรแกรมเชิงวัตถุ" ซึ่งไม่ได้ อ่านมาตรฐาน C ซึ่งไม่มีวัตถุ OOP เหล่านั้น แต่ยังมีวัตถุและค้นหา คำตอบอาจทำให้คุณประหลาดใจ!
Heath Hunnicutt

220

size_tเป็นประเภทที่ไม่ได้ลงนาม ดังนั้นจึงไม่สามารถแสดงค่าลบใด ๆ (<0) คุณใช้มันเมื่อคุณกำลังนับบางสิ่งและแน่ใจว่ามันจะไม่เป็นลบ ตัวอย่างเช่นstrlen()ส่งกลับค่า a size_tเนื่องจากความยาวของสตริงต้องมีอย่างน้อย 0

ในตัวอย่างของคุณถ้าดัชนีลูปของคุณจะมากกว่า 0 เสมอมันอาจสมเหตุสมผลที่จะใช้size_tหรือประเภทข้อมูลที่ไม่ได้ลงนามอื่น ๆ

เมื่อคุณใช้size_tวัตถุคุณต้องตรวจสอบให้แน่ใจว่าในบริบททั้งหมดที่ใช้รวมถึงคณิตศาสตร์คุณต้องการค่าที่ไม่เป็นลบ ตัวอย่างเช่นสมมติว่าคุณมี:

size_t s1 = strlen(str1);
size_t s2 = strlen(str2);

และคุณต้องการค้นหาความแตกต่างของความยาวของและstr2 str1คุณไม่สามารถทำ:

int diff = s2 - s1; /* bad */

นี่เป็นเพราะค่าที่กำหนดให้diffจะเป็นจำนวนบวกเสมอแม้ว่าจะs2 < s1คำนวณด้วยชนิดที่ไม่ได้ลงนามก็ตาม ในกรณีนี้ขึ้นอยู่กับสิ่งที่กรณีการใช้งานของคุณคือคุณอาจจะดีกว่าการใช้int(หรือlong long) สำหรับและs1s2

มีฟังก์ชั่นบางอย่างใน C / POSIX ที่สามารถ / ควรใช้size_tแต่ไม่ใช่เพราะเหตุผลทางประวัติศาสตร์ ยกตัวอย่างเช่นพารามิเตอร์ตัวที่สองที่จะfgetsควรจะต้องแต่size_tint


8
@ ถาม: คำถามสองข้อ: 1) ขนาดของsize_tคืออะไร? 2) ทำไมฉันต้องชอบsize_tอะไรมากกว่าunsigned intนี้
Lazer

2
@Lazer: ขนาดของมีsize_t sizeof(size_t)การรับรองมาตรฐาน C SIZE_MAXจะต้องมีอย่างน้อย 65535. size_tเป็นประเภทที่ส่งคืนโดยsizeofผู้ดำเนินการและใช้ในห้องสมุดมาตรฐาน (เช่นstrlenผลตอบแทนsize_t) ขณะที่เบรนแดนกล่าวว่าไม่จำเป็นต้องเป็นเช่นเดียวกับsize_t unsigned int
Alok Singhal

4
@Lazer - ใช่size_tรับประกันว่าเป็นประเภทที่ไม่ได้ลงนาม
Alok Singhal

2
@Celeritas ไม่ฉันหมายถึงประเภทที่ไม่ได้ลงชื่อสามารถแสดงถึงค่าที่ไม่เป็นลบได้เท่านั้น ฉันน่าจะพูดว่า "ไม่สามารถแทนค่าลบ"
Alok Singhal

4
@ JasonOster ส่วนประกอบสองรายการนี้ไม่ได้เป็นข้อกำหนดในมาตรฐาน C หากค่าของการs2 - s1โอเวอร์โฟintลว์พฤติกรรมจะไม่ถูกกำหนด
Alok Singhal

73

size_t เป็นประเภทที่สามารถเก็บดัชนีอาร์เรย์ใด ๆ

ขึ้นอยู่กับการนำไปใช้งานสามารถเป็นหนึ่งใน:

unsigned char

unsigned short

unsigned int

unsigned long

unsigned long long

นี่คือวิธีที่size_tกำหนดไว้ในstddef.hเครื่องของฉัน:

typedef unsigned long size_t;

4
แน่นอนtypedef unsigned long size_tขึ้นอยู่กับผู้แปล หรือคุณแนะนำว่ามันเป็นเช่นนั้นเสมอ?
chux - Reinstate Monica

4
@ chux: อันที่จริงเพียงเพราะการใช้งานหนึ่งกำหนดมันไม่ได้หมายความว่าทุกคนทำ ขนาดตัวพิมพ์: Windows 64 บิต unsigned longเป็น 32 บิตsize_tเป็น 64 บิต
ทิม Decas

2
วัตถุประสงค์ของ size_t คืออะไรกันแน่ เมื่อฉันสามารถสร้างตัวแปรให้ตัวเองเช่น: "int mysize_t;" หรือ "long mysize_t" หรือ "long mysize_t long ที่ไม่ได้ลงชื่อ" ทำไมบางคนควรสร้างตัวแปรนี้ให้ฉัน
midkin

1
@ midid size_tไม่ได้เป็นตัวแปร เป็นชนิดที่คุณสามารถใช้เมื่อคุณต้องการแสดงขนาดของวัตถุในหน่วยความจำ
Arjun Sreedharan

1
มันเป็นความจริงsize_tหรือเปล่าที่ 32 บิตบนเครื่อง 32- บิต 64 บิตเช่นกัน?
John Wu

70

ถ้าคุณเป็นประเภทเชิงประจักษ์ ,

echo | gcc -E -xc -include 'stddef.h' - | grep size_t

เอาท์พุตสำหรับ Ubuntu 14.04 GCC 64 บิต 4.8:

typedef long unsigned int size_t;

โปรดทราบว่าstddef.hมีให้โดย GCC และไม่ใช่ glibc ภายใต้src/gcc/ginclude/stddef.hใน GCC 4.2

รูปลักษณ์ C99 ที่น่าสนใจ

  • mallocใช้size_tเป็นอาร์กิวเมนต์จึงกำหนดขนาดสูงสุดที่อาจถูกจัดสรร

    และเนื่องจากมันถูกส่งคืนโดยsizeofฉันคิดว่ามัน จำกัด ขนาดสูงสุดของอาเรย์ใด ๆ

    ดูเพิ่มเติมที่: ขนาดสูงสุดของอาร์เรย์ใน C คืออะไร?


1
ฉันมีสภาพแวดล้อมเดียวกัน แต่ฉันได้ทดสอบ 32 บิตผ่านตัวเลือก "-m32" ของ GCC ผลที่ได้คือ: "typedef int size_t ที่ไม่ได้ลงนาม" ขอบคุณที่แบ่งปันคำสั่งที่ยอดเยี่ยมนี้ @Ciro มันช่วยฉันได้มาก! :-)
silvioprog

2
ตัวเองไม่สับสน มันเป็นความสับสนที่พยายามถามคำถามมากมายและให้คำตอบมากมาย ฉันประหลาดใจที่คำตอบนี้และคำตอบของ Arjun Sreedharan ยังไม่หยุดที่จะถามและตอบ
ไบโอเบอร์แมน

1
คำตอบที่ดีเพราะมันจะบอกคุณในสิ่งที่size_tเป็นอย่างน้อยใน distro ลินุกซ์ที่เป็นที่นิยม
Andrey Portnoy


19

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


คำถามของฉันคือ: ถ้าขนาดไม่เคยมีอยู่จะต้องมี size_t หรือไม่?
Dean P

@DeanP: malloc()บางทีอาจจะไม่ได้แม้ว่าจะมีก็จะมีคำถามในสิ่งที่ประเภทอาร์กิวเมนต์ควรจะใช้สำหรับสิ่งที่ต้องการ ส่วนตัวผมจะชอบที่จะมีรุ่นเห็นที่เกิดการขัดแย้งของชนิดint, longและlong longมีการใช้งานบางส่วนส่งเสริมชนิดสั้นและอื่น ๆ การดำเนินการเช่นlmalloc(long n) {return (n < 0 || n > 32767) ? 0 : imalloc(n);}[บนแพลตฟอร์มบางโทรไปimalloc(123)จะมีราคาถูกกว่าการโทรlmalloc(123);และแม้กระทั่งบนแพลตฟอร์มที่size_tคือ 16 บิตรหัสที่ต้องการจัดสรรขนาดที่คำนวณในค่า `long '...
supercat

... ควรสามารถพึ่งพาการจัดสรรที่ล้มเหลวได้หากค่ามีขนาดใหญ่กว่าตัวจัดสรรสามารถจัดการได้
supercat

11

จะเข้าไปทำไม size_tต้องมีอยู่และวิธีที่เรามาที่นี่:

ในแง่ปฏิบัติsize_tและptrdiff_tรับประกันว่าจะมีความกว้าง 64 บิตในการใช้งานแบบ 64 บิต, 32 บิตในการใช้งานแบบ 32 บิตและอื่น ๆ พวกเขาไม่สามารถบังคับประเภทที่มีอยู่ให้หมายความว่าในคอมไพเลอร์ทุกตัวโดยไม่ทำลายรหัสดั้งเดิม

size_tหรือptrdiff_tไม่จำเป็นต้องเหมือนกับหรือintptr_t uintptr_tพวกเขาแตกต่างกันไปตามสถาปัตยกรรมบางประเภทที่ยังคงใช้งานอยู่เมื่อsize_tและptrdiff_tถูกเพิ่มลงในมาตรฐานในช่วงปลายยุค 80 และล้าสมัยเมื่อ C99 ได้เพิ่มประเภทใหม่จำนวนมาก แต่ยังไม่ได้หายไป (เช่น Windows 16 บิต) x86 ในโหมดการป้องกันแบบ 16 บิตมีหน่วยความจำแบบแบ่งส่วนซึ่งอาร์เรย์หรือโครงสร้างที่ใหญ่ที่สุดที่เป็นไปได้อาจมีขนาดเพียง 65,536 ไบต์ แต่farตัวชี้จำเป็นต้องมีความกว้าง 32 บิตซึ่งกว้างกว่ารีจิสเตอร์ ในนั้นintptr_tจะได้รับ 32 บิตกว้าง แต่size_tและptrdiff_tอาจมีขนาด 16 บิตและพอดีกับการลงทะเบียน และใครจะรู้ว่าระบบปฏิบัติการแบบไหนที่จะถูกเขียนในอนาคต ในทางทฤษฎีแล้วสถาปัตยกรรม i386 เสนอรูปแบบการแบ่งเซ็กเมนต์ 32 บิตพร้อมพอยน์เตอร์ 48 บิตที่ไม่เคยใช้ระบบปฏิบัติการมาก่อน

ประเภทของออฟเซ็ตหน่วยความจำอาจไม่เป็นlongเพราะรหัสดั้งเดิมมากเกินไปถือว่าlongมีความกว้าง 32 บิต สมมติฐานนี้ถูกสร้างขึ้นใน UNIX และ Windows APIs น่าเสียดายที่รหัสมรดกอื่น ๆ จำนวนมากยังสันนิษฐานว่า a longนั้นกว้างพอที่จะถือพอยน์เตอร์ออฟเซ็ตไฟล์จำนวนวินาทีที่ผ่านไปตั้งแต่ปี 1970 เป็นต้นไป ตอนนี้ POSIX จัดเตรียมวิธีที่เป็นมาตรฐานในการบังคับให้การสันนิษฐานหลังเป็นจริงแทนที่จะเป็นแบบดั้งเดิม แต่ก็ไม่ใช่การสันนิษฐานแบบพกพา

อาจเป็นintเพราะคอมไพเลอร์เพียงเล็กน้อยเท่านั้นในยุค 90 ที่มีintความกว้าง 64 บิต จากนั้นพวกเขาก็ประหลาดจริง ๆ ด้วยการรักษาlongความกว้าง 32 บิต การแก้ไขมาตรฐานครั้งต่อไปประกาศว่าเป็นการผิดกฎหมายintที่จะกว้างกว่าlongแต่intยังคงกว้าง 32 บิตในระบบ 64 บิตส่วนใหญ่

ไม่สามารถทำได้long long intซึ่งเพิ่มเข้ามาในภายหลังเนื่องจากถูกสร้างให้มีความกว้างอย่างน้อย 64 บิตแม้ในระบบ 32 บิต

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


ไม่เห็นด้วยกับ " size_tและptrdiff_tรับประกันว่ามีความกว้าง 64 บิตในการติดตั้ง 64 บิต" ฯลฯ การรับประกันนั้นเกินเลยไป ช่วงของการsize_tขับเคลื่อนเป็นหลักโดยความจุหน่วยความจำของการใช้งาน "การปรับใช้ n-bit" เป็นความกว้างของตัวประมวลผลดั้งเดิมของจำนวนเต็ม แน่นอนว่าการใช้งานจำนวนมากใช้หน่วยความจำขนาดใกล้เคียงกันและความกว้างของตัวประมวลผลบัส แต่จำนวนเต็มแบบเนทีฟแบบกว้างที่มีหน่วยความจำไม่เพียงพอหรือตัวประมวลผลแบบแคบที่มีหน่วยความจำจำนวนมากอยู่
chux - Reinstate Monica

8

size_tและintไม่สามารถใช้แทนกันได้ ตัวอย่างเช่นบน 64-bit Linux size_tมีขนาด 64 บิต (เช่นsizeof(void*)) แต่intเป็น 32- บิต

โปรดทราบว่าไม่ได้size_tลงนาม หากคุณต้องการเวอร์ชันที่ลงชื่อแล้วมีssize_tบางแพลตฟอร์มและจะมีความเกี่ยวข้องกับตัวอย่างของคุณมากขึ้น

ตามกฎทั่วไปฉันขอแนะนำให้ใช้intสำหรับกรณีทั่วไปส่วนใหญ่และใช้size_t/ ssize_tเมื่อมีความต้องการเฉพาะเท่านั้น ( mmap()ตัวอย่างเช่น)


3

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


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

1
@ maf-soft ถูกต้อง หากตรวจพบข้อผิดพลาดจะทำให้แย่กว่าความผิดพลาดของโปรแกรม ทำไมคำตอบนี้ถึงได้ upvotes
yoyo_fun

ถ้ามันเข้าถึงข้อมูลที่ถูกต้องในอาเรย์ของคุณนั่นไม่ใช่ข้อผิดพลาดเพราะประเภทที่ไม่ได้ลงนามจะไม่ล้นที่ประเภทเซ็น จำกัด ตรรกะนี้คืออะไร? สมมติว่าด้วยเหตุผลบางอย่างที่คุณใช้ถ่านเพื่อทำซ้ำมากกว่า 256 องค์ประกอบอาร์เรย์ ... ลงนามจะล้นที่ 127 และ 128 องค์ประกอบจะ sigsegv แต่ถ้าคุณใช้ไม่ได้ลงนามก็จะผ่านทั้งอาร์เรย์ตามที่ตั้งใจ จากนั้นอีกครั้งเมื่อคุณใช้ int อาร์เรย์ของคุณจะไม่ใหญ่กว่า 2 พันล้านองค์ประกอบดังนั้นไม่ว่าจะด้วยวิธีใดก็ตาม ...
Purple Ice

1
ฉันนึกภาพไม่ออกเลยว่าสถานการณ์ใดที่จำนวนเต็มล้นไม่ใช่ข้อผิดพลาดไม่ว่าจะเป็นด้านบวกหรือด้านลบ เพียงเพราะคุณไม่ได้รับ segfault ไม่ได้หมายความว่าคุณเห็นพฤติกรรมที่ถูกต้อง! และคุณสามารถประสบกับข้อผิดพลาดในการแบ่งกลุ่มหรือไม่ว่าออฟเซ็ตของคุณเป็นบวกหรือลบ ทุกอย่างขึ้นอยู่กับรูปแบบหน่วยความจำของคุณ @ PurpleIce ฉันไม่คิดว่าคุณจะพูดแบบเดียวกันกับคำตอบนี้ อาร์กิวเมนต์ของคุณดูเหมือนว่าคุณควรเลือกประเภทข้อมูลที่มีขนาดใหญ่พอที่จะเก็บค่าที่ใหญ่ที่สุดที่คุณต้องการใส่ไว้ในนั้นซึ่งเป็นเพียงสามัญสำนึก
Soren

ที่กล่าวว่าฉันชอบใช้ประเภทที่ไม่ได้ลงนามสำหรับดัชนีวงรอบความหมาย ; หากตัวแปรของคุณไม่มีทางเป็นลบคุณก็อาจบ่งบอกได้ว่าในประเภทที่คุณเลือก นอกจากนี้ยังอาจอนุญาตให้คอมไพเลอร์พบจุดบกพร่องที่ค่าสิ้นสุดลงเป็นลบแม้ว่าอย่างน้อย GCC จะค่อนข้างแย่มากที่พบข้อผิดพลาดนี้ (ครั้งหนึ่งฉันเริ่มต้นไม่ได้ลงนามถึง -1 และไม่ได้รับคำเตือน) ในทำนองเดียวกัน size_t มีความเหมาะสมทางความหมายสำหรับดัชนีอาร์เรย์
Soren

3

size_t เป็นชนิดข้อมูลจำนวนเต็มที่ไม่ได้ลงนาม บนระบบที่ใช้ไลบรารี GNU C สิ่งนี้จะเป็น int ที่ไม่ได้ลงนามหรือ int ที่ไม่ได้ลงนามที่มีความยาว size_t ใช้กันทั่วไปสำหรับการจัดทำดัชนีอาร์เรย์และการนับลูป


1

size_tหรือประเภทที่ไม่ได้ลงนามใด ๆ อาจถูกใช้เป็นตัวแปรลูปเนื่องจากตัวแปรลูปมักจะมากกว่าหรือเท่ากับ 0

เมื่อเราใช้วัตถุsize_tเราต้องตรวจสอบให้แน่ใจว่าในบริบททั้งหมดที่ใช้รวมถึงคณิตศาสตร์เราต้องการเฉพาะค่าที่ไม่เป็นลบ ตัวอย่างเช่นโปรแกรมต่อไปนี้จะให้ผลลัพธ์ที่ไม่คาดคิด:

// C program to demonstrate that size_t or
// any unsigned int type should be used 
// carefully when used in a loop

#include<stdio.h>
int main()
{
const size_t N = 10;
int a[N];

// This is fine
for (size_t n = 0; n < N; ++n)
a[n] = n;

// But reverse cycles are tricky for unsigned 
// types as can lead to infinite loop
for (size_t n = N-1; n >= 0; --n)
printf("%d ", a[n]);
}

Output
Infinite loop and then segmentation fault

1

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

const size_t number;

size_tใช้เป็นประจำสำหรับการทำดัชนีอาเรย์และการนับลูป ถ้าคอมไพเลอร์คือมันจะทำงานบน32-bit unsigned intหากคอมไพเลอร์64-bitมันจะทำงานunsigned long long intด้วย มีขนาดสูงสุดsize_tขึ้นอยู่กับประเภทคอมไพเลอร์

size_tแล้วกำหนดใน<stdio.h>ไฟล์ส่วนหัว แต่มันยังสามารถกำหนดโดย <stddef.h>, <stdlib.h>, <string.h>, <time.h>, <wchar.h>ส่วนหัว

  • ตัวอย่าง (พร้อมconst)
#include <stdio.h>

int main()
{
    const size_t value = 200;
    size_t i;
    int arr[value];

    for (i = 0 ; i < value ; ++i)
    {
        arr[i] = i;
    }

    size_t size = sizeof(arr);
    printf("size = %zu\n", size);
}

เอาท์พุท -: size = 800


  • ตัวอย่าง (ไม่รวมconst)
#include <stdio.h>

int main()
{
    size_t value = 200;
    size_t i;
    int arr[value];

    for (i = 0 ; i < value ; ++i)
    {
        arr[i] = i;
    }

    size_t size = sizeof(arr);
    printf("size = %zu\n", size);
}

เอาท์พุท -: size = 800


-3

จากความเข้าใจของฉันsize_tเป็นunsignedจำนวนเต็มที่มีขนาดบิตใหญ่พอที่จะถือตัวชี้ของสถาปัตยกรรมพื้นเมือง

ดังนั้น:

sizeof(size_t) >= sizeof(void*)

16
ไม่จริง. size_tขนาดตัวชี้สามารถเป็นใหญ่กว่า ตัวอย่างหลายตัว: คอมไพเลอร์ C ในโหมดจริง x86 สามารถมี 32 บิตFARหรือพHUGEอยน์เตอร์ได้ แต่ size_t ยังคงเป็น 16 บิต อีกตัวอย่างหนึ่ง: Watcom C เคยมีตัวชี้ไขมันพิเศษสำหรับหน่วยความจำส่วนขยายที่มีความกว้าง 48 บิต แต่size_tไม่ใช่ ในตัวควบคุมแบบฝังที่มีสถาปัตยกรรม Harvard คุณไม่มีความสัมพันธ์ใด ๆ เนื่องจากทั้งสองเกี่ยวข้องกับพื้นที่ที่อยู่ต่างกัน
Patrick Schlüter

1
และในstackoverflow.com/questions/1572099/ …มีตัวอย่างเพิ่มเติม AS / 400 พร้อมตัวชี้ 128 บิตและ 32 บิตsize_t
Patrick Schlüter

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