अहस्ताक्षरित int बनाम size_t


492

मुझे लगता है कि आधुनिक C और C ++ कोड का उपयोग हर जगह के size_tबजाय int/ unsigned intबहुत अधिक लगता है - C स्ट्रिंग फ़ंक्शन के लिए मापदंडों से STL तक। मैं इसके कारण और इससे होने वाले लाभों के लिए उत्सुक हूं।

जवाबों:


388

size_tप्रकार अहस्ताक्षरित पूर्णांक प्रकार का परिणाम है कि है sizeofऑपरेटर (औरoffsetof इसलिए यह बहुत बड़ी सबसे बड़ी वस्तु आपके सिस्टम संभाल कर सकते हैं (जैसे, 8Gb की एक स्थिर सरणी) के आकार को रोकने के लिए होने की गारंटी है, ऑपरेटर)।

size_tप्रकार से भी बड़ा, बराबर करने के लिए, या छोटे एक से हो सकता है unsigned int, और अपने संकलक अनुकूलन के लिए इसके बारे में मान्यताओं बना सकता है।

आपको सी 99 मानक, खंड 7.17 में अधिक सटीक जानकारी मिल सकती है, जिसका एक प्रारूप इंटरनेट पर पीडीएफ प्रारूप में उपलब्ध है , या सी 11 मानक, खंड 7.19 में भी पीडीएफ प्रारूप के रूप में उपलब्ध है ।


50
नहीं। बड़े (नहीं विशाल) मेमोरी मॉडल के साथ x86-16 के बारे में सोचें: पॉइंटर्स दूर (32-बिट) हैं, लेकिन व्यक्तिगत ऑब्जेक्ट 64k (इसलिए size_t 16-bit हो सकते हैं) तक सीमित हैं।
dan04

8
"सबसे बड़ी वस्तु का आकार" खराब शब्द नहीं है, लेकिन बिल्कुल सही है। किसी वस्तु का छठा पता स्थान की तुलना में बहुत अधिक सीमित हो सकता है।
gnasher729

3
"आपका कंपाइलर इसके बारे में धारणा बना सकता है": मुझे उम्मीद है कि कंपाइलर उन मूल्यों की सटीक सीमा जानता है जो size_tप्रतिनिधित्व कर सकते हैं! यदि ऐसा नहीं होता, तो कौन करता है?
मार्क वैन लीउवेन

4
@ मेरक: मुझे लगता है कि बिंदु अधिक था कि कंपाइलर उस ज्ञान के साथ कुछ करने में सक्षम हो सकता है।

8
मैं बस यह चाहता हूं कि इस तेजी से लोकप्रिय प्रकार को हेडर फ़ाइल को शामिल करने की आवश्यकता नहीं थी।
user2023370

98

क्लासिक सी (ब्रायन केर्निघन और डेनिस रिची द्वारा सी प्रोग्रामिंग भाषा, अप्रेंटिस-हॉल, 1978 में वर्णित सी की शुरुआती बोली) प्रदान नहीं की गई size_tsize_tपोर्टेबिलिटी की समस्या को खत्म करने के लिए C मानक समिति की शुरुआत की गई

एम्बेडेड.कॉम ​​पर विस्तार से बताया गया है (बहुत अच्छे उदाहरण के साथ)


6
एक और बढ़िया लेख जो दोनों size_t और ptrdiff_t: viva64.com/en/a/0050
Ihor Kaharlichenko

73

संक्षेप में, size_t कभी भी नकारात्मक नहीं होता है, और यह प्रदर्शन को अधिकतम करता है क्योंकि यह टाइप किए गए अनिश्चित प्रकार का पूर्णांक प्रकार होना चाहिए जो काफी बड़ा है - लेकिन बहुत बड़ा नहीं है - लक्ष्य मंच पर सबसे बड़ी संभव वस्तु के आकार का प्रतिनिधित्व करने के लिए।

आकार कभी भी नकारात्मक नहीं होना चाहिए, और वास्तव size_tमें एक अहस्ताक्षरित प्रकार है। इसके अलावा, क्योंकि size_tअहस्ताक्षरित है, तो आप संख्याओं को स्टोर कर सकते हैं जो मोटे तौर पर संबंधित हस्ताक्षरित रूप में दो बार बड़े होते हैं, क्योंकि हम साइन बिट का उपयोग कर सकते हैं, जैसे कि अहस्ताक्षरित पूर्णांक में अन्य सभी बिट्स। जब हम एक और अधिक लाभ प्राप्त करते हैं, तो हम उन संख्याओं की सीमा को गुणा कर रहे हैं जिन्हें हम लगभग दो के कारक से दर्शा सकते हैं।

तो, आप पूछते हैं, क्यों नहीं बस एक का उपयोग करें unsigned int? हो सकता है कि यह बड़ी संख्या में पकड़ बनाने में सक्षम न हो। एक कार्यान्वयन में जहां unsigned int32 बिट्स है, यह सबसे बड़ी संख्या का प्रतिनिधित्व कर सकता है 4294967295। कुछ प्रोसेसर, जैसे कि IP16L32, 4294967295बाइट्स से बड़ी वस्तुओं को कॉपी कर सकते हैं ।

तो, आप पूछते हैं, क्यों नहीं एक का उपयोग करें unsigned long int? यह कुछ प्लेटफार्मों पर एक प्रदर्शन टोल को ठीक करता है। मानक सी के लिए आवश्यक है कि longकम से कम 32 बिट्स पर कब्जा हो। IP16L32 प्लेटफ़ॉर्म प्रत्येक 32-बिट को 16-बिट शब्दों की एक जोड़ी के रूप में लागू करता है। इन प्लेटफार्मों पर लगभग सभी 32-बिट ऑपरेटरों को दो निर्देशों की आवश्यकता होती है, यदि अधिक नहीं, क्योंकि वे दो 16-बिट विखंडू में 32 बिट्स के साथ काम करते हैं। उदाहरण के लिए, 32-बिट लंबे समय तक चलने के लिए आमतौर पर दो मशीन निर्देशों की आवश्यकता होती है - प्रत्येक 16-बिट चंक को स्थानांतरित करने के लिए।

का प्रयोग size_tसे बचा जाता है इस प्रदर्शन टोल। इस शानदार लेख के अनुसार , "टाइप size_tएक टाइपडिफ है जो कुछ अहस्ताक्षरित पूर्णांक प्रकार के लिए एक उपनाम है, आमतौर पर unsigned intया unsigned longलेकिन संभवतः भी unsigned long long। प्रत्येक मानक सी कार्यान्वयन को अहस्ताक्षरित पूर्णांक का चयन करना है जो कि पर्याप्त बड़ा है - लेकिन जरूरत से ज्यादा बड़ा नहीं है - लक्ष्य मंच पर सबसे बड़ी संभव वस्तु के आकार का प्रतिनिधित्व करने के लिए। "


1
इतने लंबे समय के बाद इस पर टिप्पणी करने के लिए क्षमा करें, लेकिन मुझे अभी सबसे बड़ी संख्या की पुष्टि करनी थी कि एक अहस्ताक्षरित int पकड़ सकता है - शायद मैं आपकी शब्दावली को गलत समझ रहा हूं, लेकिन मुझे लगा कि एक अहस्ताक्षरित int पकड़ सकता है 4294967295, 65356 एक अहस्ताक्षरित लघु की अधिकतम।
मिच

यदि आपका अहस्ताक्षरित इंट 32 बिट्स पर कब्जा कर लेता है, तो हाँ, इसकी सबसे बड़ी संख्या 2 ^ 32 - 1 हो सकती है, जो कि 4294967295 (0xffffffff) है। क्या आपके पास दूसरा प्रश्न है?
रोज़ पेरोन

3
@ मिच: सबसे बड़ा मूल्य जिसे कैन में दर्शाया जा सकता है unsigned intऔर यह एक सिस्टम से दूसरे सिस्टम में भिन्न होता है। यह कम से कम होना आवश्यक है 65536, लेकिन यह आमतौर पर 4294967295और 18446744073709551615कुछ प्रणालियों पर (2 ** 64-1) हो सकता है।
कीथ थॉम्पसन

1
16 बिट अहस्ताक्षरित int का सबसे बड़ा मान 65535 हो सकता है, 65536 नहीं। 65536 के रूप में एक छोटा लेकिन महत्वपूर्ण अंतर 16 बिट अहस्ताक्षरित int में 0 के समान है।
रेबॉल्ड

1
@ gnasher729: क्या आप C ++ मानक के बारे में निश्चित हैं? कुछ समय के लिए खोज करने के बाद मैं इस धारणा के अधीन हूं कि उन्होंने पूर्णांक सीमाओं (छोड़कर unsigned char) के बारे में सभी पूर्ण गारंटी को हटा दिया है । मानक में कहीं भी स्ट्रिंग '65535' या '65536' शामिल नहीं है, और '+32767' केवल नोट (1.9: 9) में संभव सबसे बड़े पूर्णांक के रूप में प्रतिनिधित्व करता है int; कोई गारंटी भी INT_MAXनहीं दी जाती है कि इससे छोटा नहीं हो सकता है!
मार्क वैन लीउवेन

51

Size_t प्रकार, sizeof ऑपरेटर द्वारा लौटाया गया प्रकार है। यह एक अहस्ताक्षरित पूर्णांक है जो मेजबान मशीन पर समर्थित किसी भी मेमोरी रेंज के बाइट्स में आकार को व्यक्त करने में सक्षम है। यह (सामान्यतया) ptrdiff_t से संबंधित है जिसमें ptrdiff_t एक हस्ताक्षरित पूर्णांक मान है जैसे कि sizeof (ptrdiff_t) और sizeof (size_t) समान हैं।

C कोड लिखते समय आपको मेमोरी रेंज के साथ काम करते समय हमेशा size_t का उपयोग करना चाहिए ।

दूसरी ओर इंट प्रकार को मूल रूप से (हस्ताक्षरित) पूर्णांक मान के आकार के रूप में परिभाषित किया गया है जिसका उपयोग मेजबान मशीन पूर्ण रूप से पूर्णांक अंकगणित करने के लिए कर सकती है। उदाहरण के लिए, कई पुराने पीसी प्रकार के कंप्यूटरों पर मूल्य sizeof (size_t) 4 (बाइट्स) होगा, लेकिन आकार (int) 2 (बाइट) होगा। 16 बिट अंकगणित 32 बिट अंकगणित से तेज था, हालांकि सीपीयू 4 गीब तक की (तार्किक) मेमोरी स्पेस को संभाल सकता था।

जब आप दक्षता के बारे में परवाह करते हैं तो इंट प्रकार का उपयोग करें क्योंकि इसकी वास्तविक परिशुद्धता कंपाइलर विकल्प और मशीन वास्तुकला दोनों पर दृढ़ता से निर्भर करती है। विशेष रूप से C मानक निम्नलिखित इनवेरिएंट्स को निर्दिष्ट करता है: sizeof (char) <= sizeof (छोटा) <= sizeof (int) <= sizeof (long) प्रत्येक के लिए प्रोग्रामर के लिए उपलब्ध परिशुद्धता के वास्तविक प्रतिनिधित्व पर कोई अन्य सीमाएं नहीं रखता है। ये आदिम प्रकार।

नोट: यह जावा के समान नहीं है (जो वास्तव में प्रत्येक प्रकार के 'चार', 'बाइट', 'शॉर्ट', 'इंट' और 'लॉन्ग') के लिए बिट परिशुद्धता को निर्दिष्ट करता है।


इंट की वास्तविक परिभाषा यह है कि यह 16 मशीनों पर 16 बिट और कुछ भी बड़े पर 32 बिट है। बहुत अधिक कोड लिखा गया है जो यह मानता है कि int 32 बिट्स चौड़ा है, इसे अब बदलने के लिए और परिणामस्वरूप लोगों को हमेशा size_t या {, u} int {8,16,32,64} _t का उपयोग करना चाहिए, यदि वे कुछ विशिष्ट चाहते हैं - - एहतियात के तौर पर, लोगों को हमेशा इंटीग्रल पूर्णांक प्रकारों के बजाय, इनका उपयोग करना चाहिए।
क्लीयर

3
"यह एक अहस्ताक्षरित पूर्णांक है जो मेजबान मशीन पर समर्थित किसी भी मेमोरी रेंज के बाइट्स में आकार को व्यक्त करने में सक्षम है।" -> नहीं। size_tकिसी भी एक वस्तु के आकार का प्रतिनिधित्व करने में सक्षम है (जैसे: संख्या, सरणी, संरचना)। संपूर्ण मेमोरी रेंज अधिक हो सकती हैsize_t
chux -

"सी कोड लिखते समय आपको मेमोरी रेंज से निपटने के लिए हमेशा size_t का उपयोग करना चाहिए।" - इसका तात्पर्य यह है कि हर सूचकांक के लिए हर सूचकांक होना चाहिए size_t- मुझे उम्मीद है कि आपका मतलब यह नहीं है। अधिकांश समय हम सरणियों से नहीं निपटते हैं जहां पते की कार्डिनैलिटी + पोर्टेबिलिटी भी मायने रखती है। इन मामलों में आप लेंगे size_t। हर दूसरे मामले में आप सूचकांकों को (हस्ताक्षरित) पूर्णांक से बाहर निकालते हैं। क्योंकि भ्रम की स्थिति (जो बिना किसी चेतावनी के आती है) अहस्ताक्षरित लोगों के अनियंत्रित व्यवहार से गिरफ्तार करना पोर्टेबिलिटी समस्याओं से अधिक सामान्य और बदतर है जो अन्य मामलों में उत्पन्न हो सकती है।
johannes_lalala 23

23

किसी भी संभावित वस्तु के आकार को संग्रहीत करने के लिए size_t पर्याप्त बड़ा होना चाहिए। अहस्ताक्षरित int को उस स्थिति को संतुष्ट नहीं करना है।

उदाहरण के लिए 64 बिट सिस्टम में int और अहस्ताक्षरित int 32 बिट वाइड हो सकते हैं, लेकिन size_t को 4G से बड़ी संख्या को संग्रहीत करने के लिए पर्याप्त होना चाहिए


38
"ऑब्जेक्ट" मानक द्वारा उपयोग की जाने वाली भाषा है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

2
मुझे लगता है size_tकि केवल इतना बड़ा होना होगा यदि कंपाइलर एक प्रकार के एक्स को स्वीकार कर सकता है जैसे कि साइज़ोफ़ (एक्स) 4 जी से बड़ा मूल्य प्राप्त करेगा। अधिकांश संकलक उदासीनता को अस्वीकार कर देंगे typedef unsigned char foo[1000000000000LL][1000000000000LL], और यहां तक foo[65536][65536];कि वैध रूप से खारिज कर दिया जा सकता है अगर यह एक प्रलेखित कार्यान्वयन-परिभाषित सीमा से अधिक हो।
सुपरकैट

1
@MattJoiner: शब्दांकन ठीक है। "ऑब्जेक्ट" बिल्कुल अस्पष्ट नहीं है, बल्कि इसका अर्थ "भंडारण का क्षेत्र" है।
ऑर्बिट

4

विषय पर शोध करते समय glibc मैनुअल 0.02 का यह अंश भी प्रासंगिक हो सकता है:

2.4 जारी करने से पहले GCC के size_t प्रकार और संस्करणों के साथ एक संभावित समस्या है। ANSI C के लिए आवश्यक है कि size_t हमेशा एक अहस्ताक्षरित प्रकार का हो। मौजूदा सिस्टम की हेडर फाइलों के साथ अनुकूलता के लिए, GCC stddef.h' to be whatever type the system'sआकार_t को sys / type.h में परिभाषित करता है। अधिकांश यूनिक्स सिस्टम जो 'sys / type.h' में size_t को परिभाषित करते हैं, इसे एक हस्ताक्षरित प्रकार मानते हैं। लाइब्रेरी में कुछ कोड size_t पर एक अहस्ताक्षरित प्रकार होने पर निर्भर करता है, और यदि यह हस्ताक्षरित है तो सही ढंग से काम नहीं करेगा।

GNU C लाइब्रेरी कोड जो साइज़_ टी को अहस्ताक्षरित करने की अपेक्षा करता है, सही है। एक हस्ताक्षरित प्रकार के रूप में size_t की परिभाषा गलत है। हमारी योजना है कि संस्करण 2.4 में, GCC हमेशा size_t को एक अहस्ताक्षरित प्रकार, और fixincludes' script will massage the system'ssys / type.h 'के रूप में परिभाषित करेगा ताकि इससे संघर्ष न हो।

इस बीच, हम जीएनयू सी लाइब्रेरी को संकलित करते समय आकार_ के लिए एक अहस्ताक्षरित प्रकार का उपयोग करने के लिए स्पष्ट रूप से जीसीसी को बताकर इस समस्या के आसपास काम करते हैं। `कॉन्फ़िगर 'स्वचालित रूप से पता लगा लेगा कि आकार_ के लिए जीसीसी किस प्रकार का उपयोग करता है यदि आवश्यक हो तो इसे ओवरराइड करने की व्यवस्था करें।


2

अगर मेरा कंपाइलर 32 बिट पर सेट है, size_tतो इसके लिए टाइपराइफ के अलावा और कुछ नहीं है unsigned int। यदि मेरा कंपाइलर 64 बिट पर सेट है, size_tतो इसके लिए टाइपराइफ के अलावा और कुछ नहीं है unsigned long long


1
केवल unsigned longकुछ OS पर दोनों मामलों के लिए परिभाषित किया जा सकता है ।
स्टेसीगर्ल

-4

size_t एक पॉइंटर का आकार है।

तो 32 बिट्स में या आम ILP32 (पूर्णांक, लंबा, सूचक) मॉडल size_t 32 बिट्स है। और 64 बिट्स या सामान्य LP64 (लंबे, पॉइंटर) मॉडल size_t में 64 बिट्स (पूर्णांक अभी भी 32 बिट्स हैं)।

अन्य मॉडल हैं लेकिन ये हैं कि जी ++ का उपयोग (कम से कम डिफ़ॉल्ट रूप से)


15
size_tजरूरी नहीं कि एक पॉइंटर के समान आकार हो, हालांकि यह आमतौर पर है। एक पॉइंटर को मेमोरी में किसी भी स्थान पर इंगित करने में सक्षम होना चाहिए; size_tकेवल सबसे बड़ी एकल वस्तु के आकार का प्रतिनिधित्व करने के लिए पर्याप्त बड़ा होना चाहिए।
कीथ थॉम्पसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.