क्या मैं 0 के मूल्य के प्रतिस्थापन के रूप में NULL का उपयोग कर सकता हूं?


73

क्या मैंने NULLसूचक को प्रतिस्थापन के रूप में उपयोग करने की अनुमति दी है 0?

या ऐसा करने में कुछ गलत है?


जैसे उदहारण के लिए:

int i = NULL;

के लिए प्रतिस्थापन के रूप में:

int i = 0;

प्रयोग के रूप में मैंने निम्नलिखित कोड संकलित किया:

#include <stdio.h>

int main(void)
{
    int i = NULL;
    printf("%d",i);

    return 0;
}

आउटपुट:

0

वास्तव में यह मुझे यह चेतावनी देता है, जो अपने आप ही पूरी तरह सही है:

warning: initialization makes integer from pointer without a cast [-Wint-conversion] 

लेकिन परिणाम अभी भी बराबर है।


  • क्या मैं इसके साथ "अपरिभाषित व्यवहार" में पार कर रहा हूं?
  • क्या NULLइस तरह से इस्तेमाल करना जायज़ है ?
  • क्या NULLअंकगणितीय अभिव्यक्तियों में संख्यात्मक मान के रूप में उपयोग करने में कुछ गड़बड़ है ?
  • और इस मामले के लिए C ++ में परिणाम और व्यवहार क्या है?

मैं का जवाब पढ़ा है क्या शून्य के बीच अंतर है '0 \' और 0, क्या बीच अंतर के बारे NULL, \0और 0है, लेकिन मैं वहाँ से संक्षिप्त जानकारी नहीं मिली है, अगर यह प्रयोग करने का अधिकार काफी अनुमति है और यह भी NULLरूप में मान असाइनमेंट और अन्य अंकगणितीय कार्यों के साथ काम करने के लिए।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
सैमुअल Liew

वास्तव में दो अलग-अलग प्रश्न पूछना बेहतर होगा, एक C के लिए और एक C ++ के लिए।
कोनराड रूडोल्फ

जवाबों:


82

क्या मैंने 0 के मान के लिए प्रतिस्थापन के रूप में NULL पॉइंटर का उपयोग करने की अनुमति दी है?

नहीं , ऐसा करना सुरक्षित नहीं है। NULLएक अशक्त सूचक है, जो टाइप कर सकता है int, लेकिन जो आमतौर पर टाइप void *(सी) में है, या अन्यथा intए (सी ++> = 11) में सीधे लागू नहीं है । दोनों भाषाएँ पॉइंटर्स को पूर्णांक में परिवर्तित करने की अनुमति देती हैं, लेकिन वे इस तरह के रूपांतरणों को अंतर्निहित रूप से निष्पादित करने के लिए प्रदान नहीं करते हैं (हालांकि कुछ संकलक इसे विस्तार के रूप में प्रदान करते हैं)। इसके अलावा, हालांकि यह मान 0 प्राप्त करने के लिए एक शून्य सूचक को पूर्णांक में परिवर्तित करने के लिए सामान्य है, मानक इसकी गारंटी नहीं देता है। यदि आप प्रकार intऔर मान 0 के साथ एक स्थिरांक चाहते हैं तो इसे वर्तनी दें 0

  • क्या मैं इसके साथ अपरिभाषित व्यवहार में पार कर सकता हूं?

हां, किसी भी कार्यान्वयन पर जहां NULLप्रकार के साथ एक मूल्य तक फैलता है void *या किसी अन्य को सीधे असाइन करने योग्य नहीं है int। इस तरह के कार्यान्वयन पर मानक आपके असाइनमेंट के व्यवहार को परिभाषित नहीं करता है, एर्गो इसका व्यवहार अपरिभाषित है।

  • क्या इस तरह NULL के साथ काम करना जायज़ है?

यह खराब शैली है, और यह कुछ प्रणालियों पर और कुछ परिस्थितियों में टूट जाएगा। यदि आप GCC का उपयोग करते हुए दिखाई देते हैं, तो यह आपके स्वयं के उदाहरण में टूट जाएगा यदि आपने -Werrorविकल्प का संकलन किया है ।

  • अंकगणितीय अभिव्यक्तियों में NULL का संख्यात्मक मान के रूप में उपयोग करने के बारे में कुछ गलत है?

हाँ। यह एक संख्यात्मक मान होने की गारंटी नहीं है। यदि आपका मतलब 0 है तो 0 लिखें, जो न केवल अच्छी तरह से परिभाषित है, बल्कि छोटा और स्पष्ट है।

  • और उस मामले में C ++ में परिणाम कैसे है?

C ++ भाषा C के मुकाबले रूपांतरणों के बारे में सख्त है और इसके लिए अलग नियम हैं NULL, लेकिन वहाँ भी, कार्यान्वयन एक्सटेंशन प्रदान कर सकते हैं। फिर, यदि आपका मतलब 0 है तो आपको यही लिखना चाहिए।


4
आपको यह इंगित करना चाहिए कि "जो अधिक आम तौर पर टाइप होता है void *" सी का केवल सच है सी void *+ + के लिए एक कानूनी प्रकार नहीं है (क्योंकि आप void*किसी अन्य पॉइंटर प्रकार को असाइन नहीं कर सकते हैं )। C ++ 89 और C ++ 03 में, वास्तव में प्रकार का NULL होना चाहिए int, लेकिन बाद के संस्करणों में यह हो सकता है (और आमतौर पर है) nullptr_t
मार्टिन बोनर मोनिका

आप यह भी गलत हैं कि अपरिभाषित व्यवहार करने के void*लिए परिवर्तित हो रहा intहै। यह नहीं; यह कार्यान्वित निर्दिष्ट व्यवहार है।
मार्टिन बोनर मोनिका

@MartinBonnersupportsMonica, उन संदर्भों में जहां C निर्दिष्ट करता है कि एक सूचक एक पूर्णांक में परिवर्तित हो जाता है, रूपांतरण का परिणाम वास्तव में कार्यान्वयन-निर्दिष्ट है, लेकिन यह वह नहीं है जो मैं बात कर रहा हूं। यह एक सूचक का पूर्णांक प्रकार के अंतराल (स्पष्ट रूप से एक डाली के माध्यम से परिवर्तित किए बिना) का एक असाइनमेंट है जिसमें अपरिभाषित व्यवहार होता है। भाषा वहां स्वचालित रूपांतरण को परिभाषित नहीं करती है।
जॉन बोलिंगर ने

@MartinBonnersupportsMonica, मैंने C ++ विचार के अधिक समावेशी होने का संपादन किया है। किसी भी घटना में, केंद्रीय विषय दोनों भाषाओं में समान रूप से लागू होता है: यदि आप पूर्णांक 0 चाहते हैं, तो इसे स्पष्ट रूप से उपयुक्त प्रकार के पूर्णांक स्थिरांक के रूप में लिखें।
जॉन बोलिंगर ने 19

31

NULLकुछ अशक्त सूचक स्थिर है। सी में यह मूल्य के साथ पूर्णांक स्थिर अभिव्यक्ति हो सकता है 0या इस तरह की अभिव्यक्ति void*बाद में होने की संभावना है। जिसका अर्थ है कि आप शून्य के साथ परस्पर उपयोग करने के लिए मान नहीं सकते हैंNULL । उदाहरण के लिए, इस कोड के नमूने में

char const* foo = "bar"; 
foo + 0;

के 0साथ प्रतिस्थापित NULLकरने के लिए एक मान्य सी प्रोग्राम होने की गारंटी नहीं है, क्योंकि दो पॉइंटर्स (अकेले अलग-अलग पॉइंटर प्रकारों के बीच अकेले) को परिभाषित नहीं किया गया है। यह एक बाधा के कारण नैदानिक ​​जारी करने का कारण होगा। जोड़ के लिए ऑपरेंड मान्य नहीं होगा


C ++ की तरह, चीजें कुछ अलग हैं। void*अन्य ऑब्जेक्ट प्रकारों से निहित रूपांतरण के अभाव का मतलब था कि NULLऐतिहासिक रूप 0से C ++ कोड के रूप में परिभाषित किया गया था । C ++ 03 में, आप शायद इससे दूर हो सकते हैं। लेकिन C ++ 11 के बाद से इसे कानूनी रूप से nullptrकीवर्ड के रूप में परिभाषित किया जा सकता है । अब फिर से एक त्रुटि का उत्पादन, क्योंकि std::nullptr_tसूचक प्रकारों में नहीं जोड़ा जा सकता है।

यदि NULLइसे परिभाषित किया जाता है nullptrतो भी आपका प्रयोग अमान्य हो जाता है। std::nullptr_tपूर्णांक से कोई रूपांतरण नहीं है । यही कारण है कि इसे एक सुरक्षित अशक्त सूचक माना जाता है।


पूर्णता के लिए, 0L एक अशक्त सूचक स्थिरांक है और इसे NULLदोनों भाषाओं में उपयोग किया जा सकता है ।
एरोरिका

1
@jamesqf मानक कहता है कि मान 0 के साथ पूर्णांक स्थिरांक एक अशक्त सूचक स्थिरांक है। इसलिए 0L एक अशक्त सूचक स्थिरांक है।
एरोरिका

1
@eororika: बस दुनिया को क्या चाहिए, मानक जो वास्तविकता को नजरअंदाज करते हैं :-) 'क्योंकि अगर मैं अपनी 80286 विधानसभा को सही ढंग से याद कर रहा हूं, तो आप एक एकल ऑपरेशन के रूप में एक दूर के सूचक को भी असाइन नहीं कर सकते हैं, इसलिए संकलक लेखकों को विशेष करना होगा -इस पर चढ़ो।
jamesqf

2
@jamesqf प्रति C FAQ , फिर से: 0एक अशक्त सूचक को स्थिर बनाना: "जाहिर है कि सभी विलोपित खराब लिखित C कोड के लिए एक सोप के रूप में, जो गलत धारणाएं बनाता है"
एंड्रयू हेनले

3
@jamesqf, मान 0 के साथ कोई भी और पूर्णांक स्थिरांक एक अशक्त-सूचक स्थिरांक है (C में) का हार्डवेयर सूचक कार्यान्वयन के साथ कोई लेना-देना नहीं है। यह भी ध्यान दें कि मानक C किसी भी मामले में निकट और दूर के बिंदुओं के बीच अंतर को नहीं पहचानता है, लेकिन पॉइंटर-टू-पॉइंटर असाइनमेंट का समर्थन करता है। यह (कुछ) पॉइंटर तुलनाओं का भी समर्थन करता है, जो 286 के जैसे खंडित संबोधित प्रारूपों के लिए दिलचस्प मुद्दे पेश करता है।
जॉन बोलिंजर

21

क्या मैंने 0 के मान के लिए NULL पॉइंटर को प्रतिस्थापन के रूप में उपयोग करने की अनुमति दी है?

int i = NULL;

नियम भाषाओं और उनके संस्करणों के बीच भिन्न होते हैं। कुछ मामलों आप में कर सकते हैं और दूसरों में, आप नहीं कर सकते। भले ही, आप नहीं करना चाहिए । यदि आप भाग्यशाली हैं, तो आपका कंपाइलर चेतावनी देगा जब आप इसे या उससे भी बेहतर प्रयास करते हैं, तो संकलन करने में विफल रहते हैं।

C ++ में, C ++ 11 से पहले (C ++ 03 से उद्धरण):

[Lib.support.types]

NULL इस अंतर्राष्ट्रीय मानक में एक कार्यान्वयन-परिभाषित C ++ नल सूचक स्थिर है।

यह एक पूर्णांक के रूप में एक अशक्त सूचक स्थिरांक का उपयोग करने के लिए बहुत कम समझ में आता है। तथापि...

[Conv.ptr]

अशक्त सूचक स्थिर पूर्णांक प्रकार का एक अभिन्न स्थिर अभिव्यक्ति (5.19) है जो शून्य का मूल्यांकन करता है।

इसलिए, यह तकनीकी रूप से काम करेगा भले ही यह निरर्थक हो। इस तकनीकीता के कारण, आप खराब लिखित कार्यक्रमों का दुरुपयोग कर सकते हैं NULL

चूंकि C ++ 11 (नवीनतम ड्राफ्ट से उद्धरण):

[Conv.ptr]

एक नल पॉइंटर लगातार शून्य मान के साथ एक पूर्णांक शाब्दिक ([lex.icon]) है या प्रकार एसटीडी की एक prvalue :: nullptr_t

A std​::​nullptr_­tपूर्णांक के लिए परिवर्तनीय नहीं है, इसलिए NULLपूर्णांक के रूप में उपयोग करना केवल सशर्त रूप से काम करेगा, जो भाषा कार्यान्वयन द्वारा किए गए विकल्पों पर निर्भर करता है।

PS nullptrएक प्रकार का प्रचलन है std​::​nullptr_­t। जब तक आपको प्री-सी ++ 11 में कंपाइल करने के लिए अपने प्रोग्राम की आवश्यकता न हो, आपको हमेशा nullptrइसके बजाय उपयोग करना चाहिए NULL


C थोड़ा अलग है (C11 ड्राफ्ट N1548 के उद्धरण)

6.3.2.3 भाषा / रूपांतरण / अन्य ऑपरेंड / पॉइंटर्स

3 0 के साथ एक पूर्णांक स्थिर अभिव्यक्ति, या टाइप करने के लिए डाली गई ऐसी अभिव्यक्तिvoid * , अशक्त सूचक स्थिरांक कहलाती है। ...

इसलिए, मामला C ++ 11 के समान है NULL। भाषा के कार्यान्वयन द्वारा चुने गए विकल्पों के आधार पर सशर्त रूप से कार्यों का दुरुपयोग ।


10

हां , हालांकि कार्यान्वयन के आधार पर आपको कलाकारों की आवश्यकता हो सकती है। लेकिन हाँ, यह 100% वैध है, अन्यथा।

हालांकि यह वास्तव में है, वास्तव में, वास्तव में खराब शैली (कहने की जरूरत नहीं है?)।

NULLहै, या था, वास्तव में नहीं सी ++, यह सी मानक है करता है लेकिन, जैसे कई सी विरासत के लिए दो खंड ([diff.null] और [support.types.nullptr]) जो तकनीकी रूप से बनाने के लिए है NULLसी ++। यह एक कार्यान्वयन-परिभाषित नल-सूचक स्थिरांक है । इसलिए, भले ही यह खराब शैली है, यह तकनीकी रूप से C ++ के रूप में है क्योंकि यह हो सकता है।
जैसा कि फुटनोट में बताया गया है , संभव कार्यान्वयन हो सकता है 0या नहीं0L , लेकिन नहीं (void*)0

NULLबेशक, (मानक स्पष्ट रूप से ऐसा नहीं कहता है, लेकिन यह बहुत ही एकमात्र विकल्प है जिसके बाद 0या शेष है 0L) nullptr। यह लगभग कभी नहीं होता है, लेकिन यह कानूनी संभावना है।

संकलक ने आपको जो चेतावनी दिखाई है, वह दर्शाता है कि संकलक वास्तव में अनुपालन नहीं है (जब तक कि आप सी मोड में संकलित नहीं किए जाते हैं)। क्योंकि, ठीक है, चेतावनी के अनुसार, इसने एक शून्य सूचक को बदल दिया ( nullptrजो नहीं होगा nullptr_t, जो अलग होगा), इसलिए जाहिर है कि परिभाषा NULLवास्तव में है (void*)0, जो कि यह नहीं हो सकती है।

किसी भी तरह से, आपके पास दो संभावित वैध (यानी संकलक टूटे हुए नहीं) मामले हैं। या तो (यथार्थवादी मामला), NULLकुछ ऐसा है 0या 0L, तो आपके पास पूर्णांक के लिए "शून्य या एक" रूपांतरण है, और आप जाने के लिए अच्छे हैं।

या NULLवास्तव में है nullptr। उस मामले में आपके पास एक अलग मूल्य है जो तुलना करने के साथ-साथ पूर्णांकों से स्पष्ट रूप से परिभाषित रूपांतरणों की गारंटी देता है , लेकिन पूरी तरह से पूर्णांकों के लिए नहीं । हालाँकि, इसका स्पष्ट रूप से परिभाषित रूपांतरण है bool(जिसके परिणामस्वरूप false), और boolपूर्णांक (जिसके परिणामस्वरूप 0) में स्पष्ट रूप से परिभाषित रूपांतरण है ।

दुर्भाग्यवश, यह दो रूपांतरण हैं, इसलिए यह "शून्य या एक" के भीतर नहीं है जैसा कि [कनव] में बताया गया है। इस प्रकार, यदि आपका कार्यान्वयन NULLजैसा परिभाषित करता है nullptr, तो आपको अपने कोड के सही होने के लिए एक स्पष्ट कलाकारों को जोड़ना होगा।


6

सी faq से:

प्रश्न: यदि NULL और 0 नल सूचक के बराबर होते हैं, तो मुझे किसका उपयोग करना चाहिए?

एक: यह केवल सूचक संदर्भों में है जो समान हैं NULLऔर 0समान हैं। दूसरी तरह की 0 की आवश्यकता होने पर इसका उपयोग नहीं किया NULLजाना चाहिए , भले ही यह काम कर सकता है, क्योंकि ऐसा करने से गलत शैलीगत संदेश जाता है। (इसके अलावा, ANSI NULL की परिभाषा को अनुमति देता है , जो गैर-पॉइंटर संदर्भों में बिल्कुल भी काम नहीं करेगा।) विशेष रूप से, उपयोग न करें।((void *)0)NULL ASCII अशक्त चरित्र (NUL) वांछित होने पर । अपनी खुद की परिभाषा प्रदान करें

http://c-faq.com/null/nullor0.html


5

अस्वीकरण: मुझे नहीं पता C ++। मेरा जवाब C ++ के संदर्भ में लागू होने का नहीं है

'\0'एक है intमूल्य शून्य के साथ सिर्फ 100% वास्तव में की तरह, 0

for (int k = 10; k > '\0'; k--) /* void */;
for (int k = 10; k > 0; k--) /* void */;

संकेत के संदर्भ में , 0और NULL100% समतुल्य हैं:

if (ptr) /* ... */;
if (ptr != NULL) /* ... */;
if (ptr != '\0') /* ... */;
if (ptr != 0) /* ... */;

सभी 100% बराबर हैं।


के बारे में ध्यान दें ptr + NULL

के संदर्भ ptr + NULLहै नहीं संकेत का है। सी भाषा में संकेत के अलावा के लिए कोई परिभाषा नहीं है; संकेत और पूर्णांक जोड़ा जा सकता है (या घटाया)। में ptr + NULLयदि या तो ptrया NULLएक सूचक है, अन्य होना चाहिए , एक पूर्णांक इसलिए ptr + NULLप्रभावी रूप से है (int)ptr + NULLया ptr + (int)NULLऔर के निर्धारण के आधार पर ptrऔर NULLकई व्यवहार उम्मीद की जा सकती: यह सब काम, सूचक और पूर्णांक, संकलित करने के लिए विफलता के बीच रूपांतरण के लिए चेतावनी, .. ।


मैंने पहले देखा है #define NULL (void *)0। क्या आप सुनिश्चित हैं कि NULL और प्लेन 0 100% समकक्ष हैं?
machine_1

2
सूचक के संदर्भ में, हां ... मेरे जवाब में शर्त पर जोर दिया गया, धन्यवाद
pmg

@ फुल्विक: मुझे C ++ के बारे में बिल्कुल पता नहीं है। मेरा उत्तर (कोष्ठक के बीच के बिट को छोड़कर)
pmg

@phuclv संकेत के संदर्भ में ptr + NULLउपयोग नहीं कर रहा NULLहै
pmg

3
@ जैस्परजहल: संकेत के संदर्भ में वे 100% समतुल्य हैं। मुझे पता नहीं क्या है nullptrहै, लेकिन ((void*)0)और 0(या '\0') संकेत के संदर्भ में बराबर हैं ...if (ptr == '\0' /* or equivalent 0, NULL */)
पीएमजी

5

नहीं, अब उपयोग करने के लिए पसंद नहीं है NULL(सूचक initization का पुराना तरीका)।

C ++ 11 के बाद से:

कीवर्ड nullptrपॉइंटर शाब्दिक को दर्शाता है। यह प्रकार std :: nullptr_t का एक प्रकार है। nullptrकिसी भी पॉइंटर प्रकार के अशक्त सूचक मान और सदस्य के प्रकार के किसी भी पॉइंटर के निहितार्थ रूपांतरण मौजूद हैं । किसी भी अशक्त सूचक स्थिरांक के लिए इसी तरह के रूपांतरण मौजूद हैं, जिसमें प्रकार के मूल्यों के std::nullptr_tसाथ-साथ मैक्रो भी शामिल है NULL

https://en.cppreference.com/w/cpp/language/nullptr

दरअसल, std :: nullptr_t , नल सूचक शाब्दिक का प्रकार है nullptr। यह एक अलग प्रकार है जो स्वयं एक सूचक प्रकार या सदस्य प्रकार के लिए एक सूचक नहीं है।

#include <cstddef>
#include <iostream>

void f(int* pi)
{
   std::cout << "Pointer to integer overload\n";
}

void f(double* pd)
{
   std::cout << "Pointer to double overload\n";
}

void f(std::nullptr_t nullp)
{
   std::cout << "null pointer overload\n";
}

int main()
{
    int* pi; double* pd;

    f(pi);
    f(pd);
    f(nullptr);  // would be ambiguous without void f(nullptr_t)
    // f(0);  // ambiguous call: all three functions are candidates
    // f(NULL); // ambiguous if NULL is an integral null pointer constant 
                // (as is the case in most implementations)
}

आउटपुट:

Pointer to integer overload
Pointer to double overload
null pointer overload

प्रश्न पूर्णांक के लिए NULL से 0 असाइन करने के बारे में है। इस अर्थ में, NULL के बजाय nullptr के साथ कुछ भी नहीं बदलता है।
ivan.ukr

उन्होंने "NULL पॉइंटर" के रूप में शब्दों का इस्तेमाल किया।
मन्नोज

वैसे, C ++ 11 के बाद C ++ की NULL अवधारणा नहीं है। लेखक विवशता का उपयोग करने के बारे में भ्रमित हो सकता है या पुराने तरीके को परिभाषित कर सकता है। en.cppreference.com/w/cpp/language/default_initialization
मन्नोज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.