Uintptr_t डेटा प्रकार क्या है


252

क्या है uintptr_tऔर इसका क्या उपयोग किया जा सकता है?


5
इस प्रकार के साथ-साथ अन्य संबंधित प्रकारों पर अतिरिक्त विवरण यहाँ उपलब्ध हैं: opengroup.org/onlinepubs/000095399/basedefs/stdint.h.html
शून्य

en.cppreference.com/w/cpp/types/integer सूचियाँ std::uintptr_tऔर std::intptr_tएक C ++ 11 वैकल्पिक।
alfC

जवाबों:


199

uintptr_tएक अहस्ताक्षरित पूर्णांक प्रकार है जो डेटा पॉइंटर को संग्रहीत करने में सक्षम है। जिसका आमतौर पर मतलब है कि यह एक पॉइंटर के समान आकार है।

यह वैकल्पिक रूप से C ++ 11 और बाद के मानकों में परिभाषित किया गया है।

किसी पूर्णांक प्रकार को प्राप्त करने का एक सामान्य कारण जो आर्किटेक्चर के पॉइंटर प्रकार को धारण कर सकता है, वह है पॉइंटर पर पूर्णांक-विशिष्ट संचालन करना, या एक पूर्णांक "हैंडल" के रूप में प्रदान करके पॉइंटर के प्रकार को अस्पष्ट करना।

संपादित करें: ध्यान दें कि स्टीव जेसप के पास कुछ और दिलचस्प विवरण हैं (जो मैं चोरी नहीं करूंगा) एक अन्य उत्तर में आपके लिए पांडित्यपूर्ण प्रकार :)


53
ध्यान दें कि size_tकेवल सबसे बड़ी वस्तु के आकार को रखने के लिए पर्याप्त होना चाहिए, और एक सूचक से छोटा हो सकता है। यह 8086 (16 बिट्स size_t, लेकिन 32 बिट्स void*) जैसे खंडित वास्तुशिल्प पर अपेक्षित होगा
MSalters

3
दो बिंदुओं के बीच अंतर का प्रतिनिधित्व करने के लिए, आपके पास है ptrdiff_tuintptr_tउस के लिए नहीं है।
jalf

3
@ जैलफ: अंतर के लिए, हां, लेकिन दूरी के लिए , आप एक अहस्ताक्षरित प्रकार चाहते हैं।
ड्रू डॉर्मन

uintptr_t परिभाषा स्पष्ट रूप से अनिवार्य नहीं है (इसलिए मानक नहीं) यहां तक ​​कि सी ++ 11 में भी नहीं! cplusplus.com/reference/cstdint (मुझे स्टीव जेसप के जवाब से संकेत मिला)
एंटोनियो

2
@MarcusJ unsigned intआमतौर पर पर्याप्त बड़ा नहीं है। लेकिन यह काफी बड़ा हो सकता है। यह प्रकार विशेष रूप से सभी "ग्रहण" को हटाने के लिए मौजूद है ।
आकर्षित डोरमैन

239

पहली बात, जिस समय यह प्रश्न पूछा uintptr_tगया था , वह C ++ में नहीं था। यह <stdint.h>वैकल्पिक प्रकार के रूप में , C99 में है । कई C ++ 03 कंपाइलर उस फ़ाइल को प्रदान करते हैं। यह C ++ 11 में भी है <cstdint>, जहां फिर से यह वैकल्पिक है, और जो परिभाषा के लिए C99 को संदर्भित करता है।

C99 में, इसे "संपत्ति के साथ एक अहस्ताक्षरित पूर्णांक प्रकार" के रूप में परिभाषित किया गया है कि शून्य के लिए किसी भी वैध सूचक को इस प्रकार में परिवर्तित किया जा सकता है, फिर वापस सूचक को शून्य में परिवर्तित किया जा सकता है, और परिणाम मूल सूचक के बराबर होगा।

इसका मतलब यह लो कि यह क्या कहता है। यह आकार के बारे में कुछ नहीं कहता है।

uintptr_tएक के रूप में एक ही आकार के हो सकता है void*। यह बड़ा हो सकता है। यह गर्भधारण करने में छोटा हो सकता है, हालांकि इस तरह का C ++ कार्यान्वयन विकृत होता है। उदाहरण के लिए, कुछ काल्पनिक प्लेटफ़ॉर्म पर जहां void*32 बिट्स हैं, लेकिन वर्चुअल एड्रेस स्पेस के केवल 24 बिट्स का उपयोग किया जाता है, आपके पास 24-बिट हो सकता है uintptr_tजो आवश्यकता को पूरा करता है। मुझे नहीं पता कि एक कार्यान्वयन ऐसा क्यों करेगा, लेकिन मानक इसकी अनुमति देता है।


8
"<Stdint.h>" के लिए धन्यवाद। मेरा आवेदन uintptr_t घोषणा के कारण संकलित नहीं हुआ। लेकिन जब मैं आपकी टिप्पणी पढ़ता हूं तो मैं "#include <stdint.h>" जोड़ता हूं और हां अब यह काम करता है। धन्यवाद!
जावारनर

2
उदाहरण के लिए, अन्य उपयोगों के बीच, संरेखित मेमोरी आवंटित करने के लिए?
लीजेंड्स 2k

4
पॉइंटर को इंट में डालने का एक और सामान्य उपयोग मामला है जो पॉइंटर को छुपाता है एक अपारदर्शी हैंडल बनाता है। यह एपीआई से एक वस्तु के संदर्भ को वापस करने के लिए उपयोगी है जहां आप ऑब्जेक्ट को लाइब्रेरी में निजी रखना चाहते हैं और एप्लिकेशन को उस तक पहुंचने से रोकते हैं। तब एप्लिकेशन को ऑब्जेक्ट पर किसी भी ऑपरेशन को करने के लिए एपीआई का उपयोग करने के लिए मजबूर किया जाता है
जोएल कनिंघम

3
@JoelCunningham: जो काम करता है लेकिन वास्तव में उपयोग करने से अलग नहीं है void*। यह संभव भविष्य की दिशाओं को प्रभावित करता है, हालांकि, खासकर यदि आप किसी ऐसी चीज का उपयोग करने के लिए बदलना चाहते हैं जो वास्तव में सिर्फ एक पूर्णांक संभालती है, तो एक परिवर्तित सूचक बिल्कुल नहीं।
स्टीव जेसोप

2
@CiroSantilli 烏坎 iro 2016 事件 ill case एक सामान्य उपयोग का मामला एक एपीआई के लिए सिर्फ एक इंट पास करना है जो सामान्य डेटा के लिए एक शून्य * की उम्मीद करता है। आपको कीस्ट्रोक्स बचाता है typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;। इसके बजाय: callback.dataPtr = (void*)val। दूसरी तरफ, आप निश्चित रूप void*से इसे प्राप्त करते हैं और इसे वापस करना पड़ता है int
फ्रांसेस्को डोंडी

19

यह एक अहस्ताक्षरित पूर्णांक प्रकार है जो एक सूचक का आकार है। जब भी आपको पॉइंटर के साथ कुछ असामान्य करने की आवश्यकता होती है - जैसे उदाहरण के लिए सभी बिट्स को उल्टा करना (यह मत पूछें कि आपने इसे क्यों डाला) uintptr_tऔर इसे एक सामान्य पूर्णांक संख्या के रूप में हेरफेर करें, तो वापस डालें।


6
बेशक आप ऐसा कर सकते थे, लेकिन यह अपरिभाषित व्यवहार होगा। मेरा मानना ​​है कि केवल एक चीज के लिए आप कास्ट के परिणाम के साथ uintptr_t अपरिवर्तित पर इसे पारित कर सकते हैं और इसे वापस डाल सकते हैं - बाकी सब यूबी है।
सालेस्के

ऐसे समय होते हैं जब आपको बिट्स के साथ खेलने की आवश्यकता होती है, और यह सामान्य रूप से संकलक त्रुटियों को उत्पन्न करेगा। एक सामान्य उदाहरण कुछ वीडियो और प्रदर्शन महत्वपूर्ण अनुप्रयोगों के लिए 16-बाइट संरेखित मेमोरी को लागू करना है। stackoverflow.com/questions/227897/…
क्लाउड

3
@ साल्सके सच नहीं है। उन मशीनों पर, जो स्व-संरेखित प्रकारों में एक सूचक के कम से कम दो महत्वपूर्ण बिट्स शून्य होने जा रहे हैं (क्योंकि पते 4 या 8 के गुणक हैं)। मैंने ऐसे प्रोग्राम देखे हैं जो डेटा को संपीड़ित करने के लिए इसका फायदा उठाते हैं ..
सादतामे

3
@saadtaame: मैंने अभी बताया कि यह C मानक के अनुसार UB है । इसका मतलब यह नहीं है कि इसे कुछ प्रणालियों पर परिभाषित नहीं किया जा सकता है - संकलक और रनटाइम्स मानक सी में यूबी है कि कुछ के लिए एक विशिष्ट व्यवहार को परिभाषित करने के लिए स्वतंत्र हैं। इसलिए कोई विरोधाभास नहीं है :-)।
सालेके

2
जरूरी नहीं कि यह पॉइंटर के आकार का ही हो। सभी मानक गारंटी यह है कि एक void*पॉइंटर वैल्यू को uintptr_tफिर से और बैक में कनवर्ट करने से ऑरिजिनल void*पॉइंटर के बराबर की तुलना में वैल्यू मिलती है। uintptr_tआमतौर पर इसका आकार एक जैसा होता है void*, लेकिन इसकी कोई गारंटी नहीं है, न ही कोई गारंटी है कि परिवर्तित मूल्य के बिट्स का कोई विशेष अर्थ है। और इस बात की कोई गारंटी नहीं है कि यह बिना सूचना के नुकसान के एक परिवर्तित पॉइंटर-टू-फंक्शन वैल्यू को होल्ड कर सकता है। अंत में, यह मौजूद होने की गारंटी नहीं है।
कीथ थॉम्पसन

15

"क्या uintptr_t डेटा प्रकार है" भाग के लिए पहले से ही कई अच्छे उत्तर हैं। मैं "इसका क्या उपयोग किया जा सकता है?" इस पोस्ट में हिस्सा।

मुख्य रूप से संकेत पर बिटवाइज़ संचालन के लिए। याद रखें कि C ++ में पॉइंटर्स पर बिटवाइज़ ऑपरेशन नहीं कर सकते हैं। कारणों से देखें कि आप C में पॉइंटर पर बिटवाइज़ ऑपरेशन क्यों नहीं कर सकते, और क्या इसके आसपास कोई रास्ता है?

इस प्रकार पॉइंटर्स पर बिटवाइज़ ऑपरेशंस करने के लिए किसी को पॉइंटर्स को Unitpr_t टाइप करना होगा और फिर बिटवाइज़ ऑपरेशंस करने होंगे।

यहाँ एक फ़ंक्शन का एक उदाहरण है जिसे मैंने XOR लिंक की गई सूची में संग्रहीत करने के लिए बिटवाइज़ एक्सक्लूसिव या 2 पॉइंटर्स करने के लिए लिखा है ताकि हम दोनों दिशाओं में एक दोहरी लिंक वाली सूची की तरह ट्रैवर्स कर सकें, लेकिन प्रत्येक नोड में 2 पॉइंटर्स को स्टोर करने के दंड के बिना। ।

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }

1
बिट अंकगणित के अलावा यह भी अच्छा है यदि आप ऑब्जेक्ट काउंट के बजाय पतों पर आधारित शब्दार्थ रखना चाहते हैं।
एलेक्स

4

एक और नेक्रोमैंसर बैज होने का जोखिम उठाते हुए, मैं uintptr_t (या यहां तक ​​कि intptr_t) के लिए एक बहुत अच्छा उपयोग जोड़ना चाहूंगा और यह परीक्षण योग्य एम्बेडेड कोड लिख रहा है। मैं ज्यादातर विभिन्न कोड और वर्तमान में टांसिलिका प्रोसेसर पर लक्षित कोड लिखता हूं। इनमें विभिन्न देशी बस चौड़ाई हैं और तनसिलिका वास्तव में अलग कोड और डेटा बसों के साथ एक हार्वर्ड वास्तुकला है जो विभिन्न चौड़ाई हो सकती है। मैं अपने बहुत से कोड के लिए एक परीक्षण संचालित विकास शैली का उपयोग करता हूं जिसका अर्थ है कि मैं सभी कोड इकाइयों के लिए इकाई परीक्षण करता हूं जो मैं लिखता हूं। वास्तविक लक्ष्य हार्डवेयर पर यूनिट परीक्षण एक परेशानी है, इसलिए मैं आमतौर पर एक इंटेल आधारित पीसी पर या तो विंडोज या लिनक्स में सब कुछ लिखता हूं जो कि काडलिंग और जीसीसी का उपयोग करता है। कहा जा रहा है, बहुत सारे एम्बेडेड कोड में बिट ट्विडलिंग और एड्रेस मैनिपुलेशन शामिल हैं। मेरी अधिकांश इंटेल मशीनें 64 बिट की हैं। इसलिए यदि आप पता हेरफेर कोड का परीक्षण करने जा रहे हैं, तो आपको गणित करने के लिए एक सामान्यीकृत ऑब्जेक्ट की आवश्यकता है। इस प्रकार uintptr_t आपको हार्डवेयर को लक्षित करने के लिए तैनात करने से पहले अपने कोड को डिबग करने का एक स्वतंत्र तरीका देता है। एक और मुद्दा कुछ मशीनों या कुछ कंपाइलरों पर मेमोरी मॉडल के लिए भी है, फ़ंक्शन पॉइंटर्स और डेटा पॉइंटर्स अलग-अलग चौड़ाई के हैं। उन मशीनों पर कंपाइलर दो वर्गों के बीच कास्टिंग की अनुमति भी नहीं दे सकता है, लेकिन uintptr_t को या तो पकड़ करने में सक्षम होना चाहिए।


निश्चित नहीं है कि क्या प्रासंगिक है ... क्या आपने "अपारदर्शी टाइपसेफ" की कोशिश की है? वीडियो: youtube.com/watch?v=jLdSjh8oqmE
shycha

@ मुझे लगता है कि सी। में उपलब्ध था, लेकिन stdint.h होने से बेहतर कुछ नहीं है। (यह भी
चाहतें हैं कि एम्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.