सूचक या पते को प्रिंट करने के लिए सही प्रारूप निर्दिष्ट करता है?


192

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

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

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

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

पता प्रिंट करने के लिए सबसे इष्टतम प्रारूप कौन सा होगा?

जवाबों:


239

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

C99 मानक (ISO / IEC 9899: 1999) §7.19.6.1 ¶8 में कहता है:

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

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

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

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

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

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

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


केरेक टिप्पणी में पूछता है:

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

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

§6.2.5 प्रकार

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

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

(C11 अनुभाग 116.2.5, and28, और फुटनोट 48 में बिल्कुल वैसा ही कहता है।)

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

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

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

§2.12.3 सूचक प्रकार

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

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

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


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

ध्यान दें कि POSIX (POSIX 2013) के एक अपडेट ने अनुभाग 2.12.3 को हटा दिया है, dlsym()इसके बजाय फ़ंक्शन की अधिकांश आवश्यकताओं को स्थानांतरित कर रहा है । एक दिन मैं बदलाव लिखूंगा ... लेकिन 'एक दिन' आज 'नहीं' है।
जोनाथन लेफ़लर

क्या यह उत्तर कार्य के लिए संकेत पर भी लागू होता है? क्या उन्हें परिवर्तित किया जा सकता है void *? हम्म मैं आपकी टिप्पणी यहाँ देख रहा हूँ । चूंकि केवल एक-वाट रूपांतरण की आवश्यकता है (फ़ंक्शन पॉइंटर टू void *), यह तब काम करता है?
chux -

@chux: कड़ाई से, उत्तर 'नहीं' है, लेकिन व्यवहार में उत्तर 'हां' है। C मानक इस बात की गारंटी नहीं देता है कि फ़ंक्शन पॉइंटर्स void *को सूचना के नुकसान के बिना a और back में परिवर्तित किया जा सकता है । व्यावहारिक रूप से, बहुत कम मशीनें हैं जहां फ़ंक्शन पॉइंटर का आकार ऑब्जेक्ट पॉइंटर के आकार के समान नहीं है। मुझे नहीं लगता कि मानक मशीनों पर एक फ़ंक्शन पॉइंटर को प्रिंट करने की एक विधि प्रदान करता है जहां था रूपांतरण समस्याग्रस्त है।
जोनाथन लेफ्लर 14

"और जानकारी के नुकसान के बिना वापस" मुद्रण के लिए प्रासंगिक नहीं है। क्या उससे मदद हुई?
chux -

50

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

int a = 42;

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

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


2
क्षमा, कास्ट को छोड़ देना "अपरिभाषित व्यवहार" क्यों है? क्या इस बात का पता है कि यह किस चर का है, अगर आपको सभी की जरूरत है तो पता है, न कि मूल्य?
वाल्डो

9
@valdo क्योंकि C यह कहता है (C99, 7.19.6.1p8) "p तर्क व्यर्थ का सूचक होगा।"
ahउह

12
@valdo: यह जरूरी नहीं है कि सभी संकेत समान आकार / प्रतिनिधित्व वाले हों।
कैफे

32

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

*) [देखें जोनाथन का ठीक जवाब!] वैकल्पिक रूप से %p, आप C99 में जोड़े गए सूचक-विशिष्ट मैक्रो का उपयोग कर सकते हैं <inttypes.h>

सभी ऑब्जेक्ट पॉइंटर्स void*C में निहित रूप से परिवर्तनीय हैं , लेकिन पॉइंटर को एक वैरिएड तर्क के रूप में पास करने के लिए, आपको इसे स्पष्ट रूप से डालना होगा (चूंकि मनमाना ऑब्जेक्ट पॉइंटर्स केवल परिवर्तनीय हैं , लेकिन शून्य पॉइंटर्स के समान नहीं हैं :

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

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

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

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

2
जोनाथन और आर .: यह सब बहुत दिलचस्प है, लेकिन मुझे पूरा यकीन है कि हम यहां फ़ंक्शन पॉइंटर्स प्रिंट करने की कोशिश नहीं कर रहे हैं, इसलिए शायद इस पर चर्चा करने के लिए यह सही जगह नहीं है। मैं बहुत बल्कि यहाँ कुछ समर्थन देखने के लिए मेरी जिद का उपयोग नहीं करना चाहते हैं %u!
केरेक एसबी

2
%uऔर सभी मशीनों%lu पर गलत हैं , कुछ मशीनों पर नहीं। का विनिर्देश बहुत स्पष्ट है कि जब टाइप किया गया प्रारूप प्रारूप के लिए आवश्यक प्रकार से मेल नहीं खाता है, तो व्यवहार अपरिभाषित है। क्या प्रकार के आकार मेल खाते हैं (जो मशीन के आधार पर सही या गलत हो सकते हैं) अप्रासंगिक है; यह ऐसे प्रकार हैं जिनका मिलान होना चाहिए, और वे कभी नहीं होंगे। printf
R .. गिटहब स्टॉप हेल्पिंग ICE

9

अन्य (बहुत अच्छे) उत्तरों के विकल्प के रूप में, आप ( uintptr_tया / से ) कास्ट कर सकते हैं और संबंधित पूर्णांक रूपांतरण विनिर्देशक का उपयोग कर सकते हैं। यह सूचक को स्वरूपित करने के तरीके में अधिक लचीलापन देता है, लेकिन इन टंकणों को प्रदान करने के लिए सख्ती से कार्यान्वयन की आवश्यकता नहीं है।intptr_tstdint.hinttypes.h


विचार करें #include <stdio.h> int main(void) { int p=9; int* m=&s; printf("%u",m); } कि %uक्या प्रारूप विनिर्देशक का उपयोग करके चर का पता प्रिंट करना अपरिभाषित व्यवहार है ? अधिकांश मामलों में परिवर्तनशील का पता सकारात्मक है तो क्या मैं %uइसके बजाय उपयोग कर सकता हूं %p?
नाशक

1
@ डीस्ट्रक्टर: नहीं, प्रकार के %uलिए एक प्रारूप है unsigned intऔर इसका उपयोग पॉइंटर तर्क के साथ नहीं किया जा सकता है printf
आर .. गिटहब स्टॉप हेल्पिंग ICE

-1

आप उपयोग कर सकते हैं %xया %Xया %p; वे सभी सही हैं।

  • यदि आप उपयोग करते हैं %x, तो पता निम्न के रूप में दिया जाता है, उदाहरण के लिए:a3bfbc4
  • यदि आप उपयोग करते हैं %X, तो पते को अपरकेस के रूप में दिया जाता है, उदाहरण के लिए:A3BFBC4

ये दोनों सही हैं।

यदि आप पते के लिए छह पदों का उपयोग करते हैं %xया %Xविचार कर रहे हैं, और यदि आप इसका उपयोग %pकरते हैं तो पते के लिए आठ पदों पर विचार कर रहे हैं। उदाहरण के लिए:


1
एसओ में आपका स्वागत है। कृपया अन्य उत्तरों की समीक्षा करने के लिए कुछ समय लें, वे स्पष्ट रूप से बता रहे हैं कि आप कितने विवरणों को देख रहे हैं।
एंटोनील
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.