c - size_t बनाम uintptr_t




pointers size-t (5)

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

void *v = malloc(10);
size_t s = (size_t) v;

तो फिर सी 99 में, मानक ने intptr_t और uintptr_t प्रकारों को प्रस्तुत किया, जो हस्ताक्षर किए गए हैं और हस्ताक्षरित प्रकार पॉइंटर्स को पकड़ने में सक्षम होने की गारंटी है:

uintptr_t p = (size_t) v;

तो size_t और uintptr_t का उपयोग करने के बीच क्या अंतर है? दोनों हस्ताक्षरित हैं, और दोनों किसी भी सूचक प्रकार को पकड़ने में सक्षम होना चाहिए, इसलिए वे कार्यात्मक रूप से समान लगते हैं। स्पष्टता के अलावा, size_t बजाय uintptr_t (या बेहतर अभी तक, एक void * ) का उपयोग करने के लिए कोई वास्तविक uintptr_t कारण है? एक अपारदर्शी संरचना में, जहां क्षेत्र केवल आंतरिक कार्यों द्वारा संभाला जाएगा, क्या ऐसा करने का कोई कारण नहीं है?

एक ही टोकन द्वारा, ptrdiff_t पॉइंटर मतभेद रखने में सक्षम एक हस्ताक्षरित प्रकार रहा है, और इसलिए किसी भी पॉइंटर को पकड़ने में सक्षम है, तो यह intptr_t से अलग कैसे है?

क्या इन सभी प्रकारों में मूल रूप से एक ही कार्य के तीन अलग-अलग संस्करणों की सेवा नहीं कर रहे हैं? यदि नहीं, क्यों? मैं उनमें से एक के साथ क्या नहीं कर सकता कि मैं किसी और के साथ नहीं कर सकता? यदि हां, तो सी 99 ने भाषा में दो अनिवार्य रूप से अनिवार्य प्रकार क्यों जोड़े?

मैं फंक्शन पॉइंटर्स को नजरअंदाज करने के लिए तैयार हूं, क्योंकि वे वर्तमान समस्या पर लागू नहीं होते हैं, लेकिन उन्हें जिक्र करने में संकोच न करें, क्योंकि मुझे संदेह है कि वे "सही" उत्तर के लिए केंद्र होंगे।


size_t एक प्रकार है जो किसी भी सरणी अनुक्रमणिका को पकड़ सकता है। इसका मतलब यह है कि, तार्किक रूप से, size_t किसी भी सूचक प्रकार को पकड़ने में सक्षम होना चाहिए

जरुरी नहीं! उदाहरण के लिए खंडित 16-बिट आर्किटेक्चर के दिनों में हार्क करें: एक सरणी एक सेगमेंट तक सीमित हो सकती है (इसलिए 16-बिट size_t करेगा) लेकिन आपके पास एकाधिक सेगमेंट हो सकते हैं (इसलिए 32-बिट intptr_t प्रकार की आवश्यकता होगी सेगमेंट के साथ-साथ ऑफसेट को चुनने के लिए)। मुझे इन चीजों को समान रूप से संबोधित करने योग्य अनगिनत आर्किटेक्चर के इन दिनों में अजीब लगता है, लेकिन मानक को "200 9 में सामान्य क्या है" की तुलना में व्यापक विविधता के लिए पूरा करना चाहिए, आपको पता है! -)


आपके बयान के बारे में:

"सी मानक गारंटी देता है कि size_t एक प्रकार है जो किसी भी सरणी इंडेक्स को पकड़ सकता है। इसका मतलब है कि, तार्किक रूप से, size_t किसी भी सूचक प्रकार को पकड़ने में सक्षम होना चाहिए।"

इसे गलतता कहा जाता है, गलत तर्क से उत्पन्न एक गलतफहमी। आप सोच सकते हैं कि उत्तरार्द्ध पूर्व से है लेकिन यह जरूरी नहीं है।

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

सी 99 का कहना है कि size_t चर की ऊपरी सीमा SIZE_MAX द्वारा परिभाषित की गई है और यह 65535 जितनी कम हो सकती है (सी 99 टीआर 3, 7.18.3 देखें, सी 11 में अपरिवर्तित)। अगर वे आधुनिक प्रणालियों में इस सीमा तक सीमित थे तो पॉइंटर्स काफी सीमित होंगे।

अभ्यास में, आपको शायद पता चलेगा कि आपकी धारणा है, लेकिन ऐसा इसलिए नहीं है क्योंकि मानक इसकी गारंटी देता है। क्योंकि यह वास्तव में इसकी गारंटी नहीं देता है।


मैं कल्पना करता हूं (और यह सभी प्रकार के नामों के लिए जाता है) यह कोड में आपके इरादों को बेहतर ढंग से व्यक्त करता है।

उदाहरण के लिए, भले ही unsigned short और wchar_t विंडोज़ (मुझे लगता है) पर एक ही आकार के हैं, unsigned short बजाय wchar_t का उपयोग करके यह इरादा दिखाता है कि आप इसे कुछ मनमाना संख्या के बजाए विस्तृत चरित्र को स्टोर करने के लिए उपयोग करेंगे।


यह संभव है कि सबसे बड़ी सरणी का आकार एक सूचक से छोटा है। सेगमेंट आर्किटेक्चर के बारे में सोचें - पॉइंटर्स 32-बिट हो सकते हैं, लेकिन एक सेगमेंट केवल 64 केबी को संबोधित करने में सक्षम हो सकता है (उदाहरण के लिए पुराना वास्तविक मोड 8086 आर्किटेक्चर)।

हालांकि ये आमतौर पर डेस्कटॉप मशीनों में उपयोग में नहीं हैं, सी मानक का उद्देश्य छोटे, विशेष आर्किटेक्चर का समर्थन करना है। उदाहरण के लिए अभी भी 8 या 16 बिट CPUs के साथ एम्बेडेड सिस्टम विकसित किए जा रहे हैं।


int main(){
  int a[4]={0,1,5,3};
  int a0 = a[0];
  int a1 = *(a+1);
  int a2 = *(2+a);
  int a3 = 3[a];
  return a2;
}

यह बताते हुए कि intptr_t हमेशा size_t और वीज़ा बनाम के लिए प्रतिस्थापित होना चाहिए।





size-t