2012-01-29 15 views
112

एक चर के पते को मुद्रित करने के लिए मुझे किस प्रारूप विनिर्देशक का उपयोग करना चाहिए? मैं नीचे के बीच उलझन में हूँ।संकेतक मुद्रित करने के लिए सही प्रारूप निर्दिष्ट (पता)?

% u - अहस्ताक्षरित पूर्णांक

% x - हेक्साडेसिमल मान

% p - शून्य सूचक

कौन सा एक पते मुद्रित करने के लिए इष्टतम प्रारूप हो सकता है?

उत्तर

133

सरल जवाब है, यह मानते हुए कि अनियमितता और विभिन्न प्लेटफार्मों के बीच प्रारूप में बदलाव से परहेज नहीं करते, मानक %p अंकन है।

C99 मानक (आईएसओ/आईईसी 9899: 1999) का कहना है §7.19.6.1 में ¶8:

p तर्क void के लिए सूचक होगा। पॉइंटर का मान कार्यान्वयन-परिभाषित तरीके से प्रिंटिंग वर्णों के अनुक्रम में परिवर्तित किया गया है।

(सी 11 में - आईएसओ/आईईसी 9899: 2011 - जानकारी §7.21.6.1 ¶8 में है।)

कुछ प्लेटफार्मों पर, कि एक प्रमुख 0x और दूसरों पर ऐसा नहीं होगा शामिल होंगे , और पत्र निचले मामले या ऊपरी मामले में हो सकते हैं, और सी मानक यह भी परिभाषित नहीं करता है कि यह हेक्साडेसिमल आउटपुट होगा हालांकि मुझे पता नहीं है कि यह कोई कार्यान्वयन नहीं है।

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

आप %p के कार्यान्वयन से परिभाषित व्यवहार से खुश नहीं हैं, तो C99 <inttypes.h> और uintptr_t बजाय का उपयोग करें:

printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer); 

यह आप फ़ाइन-ट्यून करने के लिए अपने आप को सूट करने के लिए प्रतिनिधित्व अनुमति देता है। मैंने ऊपरी मामले में हेक्स अंकों को चुना है ताकि संख्या समान रूप से एक ही ऊंचाई हो और 0xA1B2CDEF की शुरुआत में विशेषता डुबकी इस प्रकार दिखाई दे, 0xa1b2cdef जो संख्या के साथ ऊपर और नीचे डुबकी नहीं है। आपकी पसंद हालांकि, बहुत व्यापक सीमाओं के भीतर। (uintptr_t) कास्ट जीसीसी द्वारा अनजाने में अनुशंसित किया जाता है जब यह संकलन समय पर प्रारूप स्ट्रिंग को पढ़ सकता है। मुझे लगता है कि कलाकारों का अनुरोध करना सही है, हालांकि मुझे यकीन है कि कुछ ऐसे हैं जो चेतावनी को अनदेखा करते हैं और अधिकांश समय से दूर हो जाते हैं।


Kerrek टिप्पणी में पूछते हैं:

मैं थोड़ा मानक प्रचार और variadic तर्क के बारे में उलझन में हूँ। क्या सभी पॉइंटर्स मानक * को शून्य से प्रचारित करते हैं? अन्यथा, अगर int* कहें, दो बाइट्स, और void* 4 बाइट थे, तो यह तर्क से चार बाइट पढ़ने के लिए स्पष्ट रूप से एक त्रुटि होगी, न?

मैं भ्रम के तहत किया गया है कि सी मानक कहना है कि सभी वस्तु संकेत दिए गए, एक ही आकार होना चाहिए, ताकि void * और int * विभिन्न आकारों नहीं हो सकता। हालांकि, मुझे लगता है कि C99 मानक के प्रासंगिक अनुभाग है नहीं तो जोरदार (हालांकि मैं एक कार्यान्वयन जहां मैं क्या सुझाव दिया सच है की नहीं जानता है वास्तव में गलत) है:

§6.2.5 प्रकार

¶26 शून्य के लिए एक सूचक के पास एक चरित्र प्रकार के सूचक के रूप में समान प्रतिनिधित्व और संरेखण आवश्यकताएं होंगी। 39) इसी तरह, संगत प्रकार के योग्य या अयोग्य संस्करणों के पॉइंटर्स के समान प्रतिनिधित्व और संरेखण आवश्यकताएं होंगी। संरचना प्रकारों के सभी पॉइंटर्स में एक दूसरे के समान प्रतिनिधित्व और संरेखण आवश्यकताएं होंगी। यूनियन प्रकारों के सभी पॉइंटर्स के पास एक-दूसरे के समान प्रतिनिधित्व और संरेखण आवश्यकताएं होंगी। अन्य प्रकार के पॉइंटर्स को समान प्रतिनिधित्व या संरेखण आवश्यकताओं की आवश्यकता नहीं होती है।

39) समान प्रतिनिधित्व और संरेखण आवश्यकताओं का मतलब है कि कार्यों के तर्क के रूप में, कार्यों से मूल्यों को वापस करने, और संघों के सदस्यों के रूप में अंतरणशीलता को इंगित करने के लिए।

(सी 11 अनुभाग §6.2.5, ¶28, और फुटनोट 48 में बिल्कुल वही कहता है।)

तो, सभी पॉइंटर्स संरचनाओं को एक दूसरे के समान आकार होना चाहिए, और उसी संरेखण आवश्यकताओं को साझा करना होगा, भले ही पॉइंटर्स बिंदुओं की संरचनाओं में अलग-अलग संरेखण आवश्यकता हो। इसी तरह संघों के लिए। कैरेक्टर पॉइंटर्स और शून्य पॉइंटर्स के पास समान आकार और संरेखण आवश्यकताएं होनी चाहिए। int (unsigned int और signed int पर भिन्नता के लिए पॉइंटर्स) एक दूसरे के समान आकार और संरेखण आवश्यकताएं होनी चाहिए; इसी प्रकार अन्य प्रकार के लिए। लेकिन सी मानक औपचारिक रूप से नहीं कहता है कि sizeof(int *) == sizeof(void *)। ओह ठीक है, आपको अपनी धारणाओं का निरीक्षण करने के लिए अच्छा है।

सी मानक निश्चित रूप से फ़ंक्शन पॉइंटर्स को ऑब्जेक्ट पॉइंटर्स के समान आकार की आवश्यकता नहीं है। यह आवश्यक था कि डॉस-जैसी प्रणालियों पर विभिन्न मेमोरी मॉडल को तोड़ना न पड़े। वहां आपके पास 16-बिट डेटा पॉइंटर्स हो सकते हैं लेकिन 32-बिट फ़ंक्शन पॉइंटर्स, या इसके विपरीत। यही कारण है कि सी मानक यह जरूरी नहीं है कि फ़ंक्शन पॉइंटर्स को ऑब्जेक्ट पॉइंटर्स में परिवर्तित किया जा सके और इसके विपरीत।

सौभाग्य से (इसे POSIX लक्ष्यीकरण प्रोग्रामर के लिए), POSIX उल्लंघन में कदम और जनादेश है कि समारोह संकेत और डेटा संकेत दिए गए एक ही आकार के होते हैं:

§2.12.3 Pointer Types

सभी समारोह सूचक प्रकार टाइप पॉइंटर को रद्द करने के समान ही प्रतिनिधित्व होगा। फ़ंक्शन पॉइंटर का रूपांतरण void * पर रूपांतरण प्रस्तुत नहीं करेगा। इस तरह के रूपांतरण से उत्पन्न void * मूल्य को जानकारी के नुकसान के बिना, एक स्पष्ट कलाकार का उपयोग करके मूल फ़ंक्शन पॉइंटर प्रकार में वापस परिवर्तित किया जा सकता है।

नोट: आईएसओ सी मानक की आवश्यकता नहीं है, लेकिन यह POSIX अनुरूपता के लिए आवश्यक है।

इसलिए, यह है कि void * को स्पष्ट डाले कोड में अधिकतम विश्वसनीयता के लिए दृढ़ता से सलाह दी जाती हैं प्रतीत होता है जब इस तरह के printf() के रूप में एक variadic कार्य करने के लिए एक सूचक गुजर। POSIX सिस्टम पर, प्रिंटिंग के लिए एक शून्य सूचक को फ़ंक्शन पॉइंटर डालना सुरक्षित है। अन्य प्रणालियों पर, ऐसा करने के लिए जरूरी नहीं है, और न ही किसी भी कलाकार के बिना void * के अलावा पॉइंटर्स को पास करना सुरक्षित है।

+3

मैं मानक प्रचार और विविध तर्कों के बारे में थोड़ा उलझन में हूं। क्या सभी पॉइंटर्स को 'शून्य *' के लिए मानक-प्रचारित किया जाता है? अन्यथा, यदि 'int *' कहें, तो दो बाइट्स, और 'शून्य * '4 बाइट थे, तो यह तर्क से चार बाइट पढ़ने के लिए स्पष्ट रूप से एक त्रुटि होगी, न? –

+0

ध्यान दें कि POSIX (POSIX 2013) के लिए एक अद्यतन ने खंड 2.12.3 को हटा दिया है, जो अधिकांश आवश्यकताओं को ['dlsym()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym) में ले जा रहा है .html) इसके बजाए कार्य करें। एक दिन मैं परिवर्तन लिखूंगा ... लेकिन 'एक दिन' 'आज' नहीं है। –

+0

क्या यह उत्तर पॉइंटर्स पर फ़ंक्शंस पर भी लागू होता है? क्या उन्हें 'शून्य *' में परिवर्तित किया जा सकता है? हम्म मैं आपकी टिप्पणी देखता हूं [यहां] (http://stackoverflow.com/questions/9053658/correct-format-specifier-to-print-pointer-address#comment11360489_9053677)। चूंकि केवल एक-वाट रूपांतरण की आवश्यकता है ('शून्य *' पर फ़ंक्शन पॉइंटर), तो यह तब काम करता है? – chux

28

p प्रिंट पॉइंटर्स के लिए रूपांतरण विनिर्देशक है। इसे इस्तेमाल करो।

int a = 42; 

printf("%p\n", (void *) &a); 

याद रखें कि कलाकारों को छोड़ते हुए अपरिभाषित व्यवहार और p रूपांतरण विनिर्देशक एक कार्यान्वयन से परिभाषित तरीके से किया जाता है के साथ कि मुद्रण है।

+0

माफ़ी, क्यों कास्ट छोड़ना "अपरिभाषित व्यवहार" है? क्या इससे कोई फर्क नहीं पड़ता कि यह किस वैरिएबल है, अगर आपको केवल इतना पता है, तो मूल्य नहीं है? – valdo

+8

@ वाल्डो क्योंकि सी कहते हैं (सी 99, 7.1 9.6.1 पी 8) "पी तर्क शून्य के लिए एक सूचक होगा।" – ouah

+9

@ वाल्डो: यह जरूरी नहीं है कि सभी पॉइंटर्स एक ही आकार/प्रतिनिधित्व हों। – caf

21

"पॉइंटर" के लिए %p का उपयोग करें, और किसी और चीज का उपयोग न करें *। आपको मानक द्वारा गारंटी नहीं दी जाती है कि आपको किसी विशेष प्रकार के पूर्णांक की तरह पॉइंटर का इलाज करने की अनुमति है, इसलिए आपको वास्तव में अभिन्न स्वरूपों के साथ अपरिभाषित व्यवहार प्राप्त होगा। (उदाहरण के लिए, %u एक unsigned int, लेकिन उम्मीद है क्या हुआ अगर void* एक अलग आकार या unsigned int से संरेखण आवश्यकता? है)

*) %p को वैकल्पिक रूप से [जोनाथन के ठीक जवाब मिलते हैं!], आप कर सकते हैं उपयोग सूचक विशेष मैक्रोसे, सी 99 में जोड़ा गया।

सभी वस्तु संकेत परोक्ष सी में void* के लिए परिवर्तनीय हैं, लेकिन आदेश में एक variadic तर्क के रूप में सूचक पारित करने के लिए, आप इसे स्पष्ट रूप से कास्ट करने के लिए है (के बाद से मनमाना वस्तु संकेत केवल परिवर्तनीय, लेकिन नहीं समान लिए कर रहे हैं शून्य संकेत):

printf("x lives at %p.\n", (void*)&x); 
+2

सभी * ऑब्जेक्ट * पॉइंटर्स परिवर्तनीय 'void *' (हालांकि 'printf()' के लिए आपको तकनीकी रूप से स्पष्ट कलाकारों की आवश्यकता है, क्योंकि यह एक विविध कार्य है)। फंक्शन पॉइंटर्स जरूरी रूप से परिवर्तनीय नहीं हैं 'शून्य *'। – caf

+0

@caf: ओह, मुझे विविध तर्कों के बारे में पता नहीं था - निश्चित! धन्यवाद! –

+2

मानक सी की आवश्यकता नहीं है कि फ़ंक्शन पॉइंटर्स परिवर्तनीय हो जाएं 'void *' और बिना किसी नुकसान के फ़ंक्शन पॉइंटर पर; सौभाग्य से, हालांकि, POSIX स्पष्ट रूप से इसकी आवश्यकता है (यह नोट करते हुए कि यह मानक सी का हिस्सा नहीं है)। तो, व्यावहारिक रूप से, आप इसके साथ दूर हो सकते हैं ('शून्य (* फ़ंक्शन) (शून्य) 'से' शून्य *' और वापस 'शून्य (* फ़ंक्शन) (शून्य)' में परिवर्तित कर सकते हैं, लेकिन सख्ती से यह अनिवार्य नहीं है सी मानक। –

8

अन्य (बहुत अच्छा) जवाब के लिए एक विकल्प के रूप में, आप (stdint.h/inttypes.h से) uintptr_t या intptr_t लिए डाली सकता है और इसी पूर्णांक रूपांतरण विनिर्देशक का उपयोग करें। यह पॉइंटर को स्वरूपित करने में अधिक लचीलापन की अनुमति देगा, लेकिन इन टाइपिफ को प्रदान करने के लिए कड़ाई से एक कार्यान्वयन की आवश्यकता नहीं है।

+0

नाइस के पूर्व इतिहास में बहुत सारी चीज़ें अलग थीं, नाइस को 'uintptr_t' के बारे में पता नहीं था। – cnicutar

+0

पर विचार करें # # शामिल करें int मुख्य (शून्य) {int p = 9; int * m = & s; printf ("% u", मी); } '__ यह'% u' प्रारूप विनिर्देशक का उपयोग कर चर के पते को मुद्रित करने के लिए अपरिभाषित व्यवहार है? __ अधिकांश मामलों में चर का पता सकारात्मक है, तो क्या मैं '% p' के बजाय'% u' का उपयोग कर सकता हूं? – Destructor

+0

@ निर्माता: नहीं, '% u' 'हस्ताक्षरित int' प्रकार के लिए एक प्रारूप है और' printf' के लिए पॉइंटर तर्क के साथ उपयोग नहीं किया जा सकता है। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^