क्या %p
रूपांतरण विनिर्देशक के साथ अशक्त बिंदुओं को प्रिंट करना अपरिभाषित व्यवहार है ?
#include <stdio.h>
int main(void) {
void *p = NULL;
printf("%p", p);
return 0;
}
प्रश्न सी मानक पर लागू होता है, और सी कार्यान्वयन पर नहीं।
क्या %p
रूपांतरण विनिर्देशक के साथ अशक्त बिंदुओं को प्रिंट करना अपरिभाषित व्यवहार है ?
#include <stdio.h>
int main(void) {
void *p = NULL;
printf("%p", p);
return 0;
}
प्रश्न सी मानक पर लागू होता है, और सी कार्यान्वयन पर नहीं।
जवाबों:
यह उन अजीब कोने के मामलों में से एक है जहां हम अंग्रेजी भाषा की सीमाओं और मानक में असंगत संरचना के अधीन हैं। तो सबसे अच्छा, मैं एक सम्मोहक काउंटर-तर्क कर सकता हूं, क्योंकि यह साबित करना असंभव है :) 1
प्रश्न में कोड अच्छी तरह से परिभाषित व्यवहार प्रदर्शित करता है।
जैसा कि [let's.१.४] प्रश्न का आधार है, चलिए शुरू करते हैं:
निम्नलिखित विवरणों में से प्रत्येक तब तक लागू होता है जब तक कि स्पष्ट रूप से विस्तृत विवरणों में अन्यथा स्पष्ट रूप से कहा गया हो, जो अनुसरण नहीं करते हैं: यदि किसी फ़ंक्शन के तर्क में अमान्य मान है ( जैसे कि फ़ंक्शन के डोमेन के बाहर का मान, या प्रोग्राम के पता स्थान के बाहर एक संकेतक, या अशक्त सूचक , [... अन्य उदाहरण ...] ) [...] व्यवहार अपरिभाषित है। [... अन्य कथन ...]
यह अनाड़ी भाषा है। एक व्याख्या यह है कि सूची में आइटम सभी पुस्तकालय कार्यों के लिए यूबी हैं, जब तक कि व्यक्तिगत विवरण द्वारा ओवरराइड नहीं किया जाता है। लेकिन सूची "जैसे" से शुरू होती है, यह दर्शाता है कि यह उदाहरणात्मक है, संपूर्ण नहीं। उदाहरण के लिए, यह स्ट्रिंग्स के सही शून्य-समाप्ति का उल्लेख नहीं करता है (उदाहरण के लिए महत्वपूर्ण strcpy
)।
इस प्रकार यह स्पष्ट है कि is.१.४ का इरादा / दायरा केवल इतना है कि एक "अमान्य मूल्य" यूबी की ओर जाता है ( जब तक कि अन्यथा नहीं कहा जाता है )। हमें प्रत्येक फ़ंक्शन के विवरण को यह देखने के लिए देखना होगा कि "अमान्य मान" के रूप में क्या मायने रखता है।
strcpy
[[.२१.२.३] केवल यही कहता है:
strcpy
समारोह प्रतियां स्ट्रिंग द्वारा की ओर इशारा कियाs2
(समाप्त अशक्त चरित्र सहित) सरणी में से की ओर इशारा कियाs1
। यदि ओवरलैप करने वाली वस्तुओं के बीच नकल होती है, तो व्यवहार अपरिभाषित है।
यह शून्य बिंदुओं का कोई स्पष्ट उल्लेख नहीं करता है, फिर भी यह शून्य टर्मिनलों का कोई उल्लेख नहीं करता है। इसके बजाय, "स्ट्रिंग द्वारा इंगित किया गया s2
" से एक infers कि केवल मान्य मान स्ट्रिंग हैं (यानी वर्ण-निरपेक्ष वर्ण सरणियों को इंगित करता है )।
वास्तव में, इस पैटर्न को पूरे व्यक्तिगत विवरण में देखा जा सकता है। कुछ अन्य उदाहरण:
[[.६.४.१ (fenv)] द्वारा इंगित की गई वस्तु में वर्तमान फ्लोटिंग-पॉइंट पर्यावरण को संग्रहीत करें
envp
[7.12.6.4 (frexp)] पूर्णांक में पूर्णांक की दुकान की ओर इशारा किया वस्तु से
exp
[7.19.5.1 (fclose)] धारा की ओर इशारा द्वारा
stream
printf
[[.१ ९ .६.१] इसके बारे में कहते हैं %p
:
p
- तर्क एक सूचक होगाvoid
। सूचक का मान कार्यान्वयन-परिभाषित तरीके से, मुद्रण वर्णों के अनुक्रम में परिवर्तित हो जाता है।
नल एक मान्य पॉइंटर मान है, और यह खंड कोई स्पष्ट उल्लेख नहीं करता है कि नल एक विशेष मामला है, और न ही सूचक को किसी ऑब्जेक्ट पर इंगित करना है। इस प्रकार यह परिभाषित व्यवहार है।
1. जब तक एक मानक लेखक आगे नहीं आता है, या जब तक कि हम चीजों को स्पष्ट करने वाले औचित्य दस्तावेज के समान कुछ नहीं पा सकते हैं।
जी हां । %p
रूपांतरण निर्दिष्ट के साथ मुद्रण नल बिंदुओं का अपरिभाषित व्यवहार होता है। यह कहने के बाद, मैं किसी भी मौजूदा अनुरूप कार्यान्वयन से अनजान हूँ जो दुर्व्यवहार करेगा।
उत्तर सी मानकों (C89 / C99 / C11) में से किसी पर लागू होता है।
%p
रूपांतरण विनिर्देशक शून्य करने के लिए प्रकार सूचक की एक बहस की उम्मीद है, प्रिंट करने योग्य पात्रों को सूचक के रूपांतरण कार्यान्वयन परिभाषित किया गया है। यह बताता है कि अशक्त सूचक अपेक्षित नहीं है।
मानक लाइब्रेरी फ़ंक्शंस का परिचय बताता है कि जब तक कि यह स्पष्ट रूप से अन्यथा नहीं कहा जाता है, तब तक (मानक लाइब्रेरी) फ़ंक्शन के लिए अशक्त संकेत अमान्य मान माने जाते हैं।
C99
/ C11
§7.1.4 p1
[...] यदि किसी फ़ंक्शन के तर्क में एक अमान्य मान है (जैसे [...] एक अशक्त सूचक, [...] व्यवहार अपरिभाषित है।
मान्य मानक के रूप में अशक्त बिंदुओं की अपेक्षा करने वाले (मानक पुस्तकालय) कार्यों के उदाहरण:
fflush()
"सभी स्ट्रीम" (जो लागू होता है) को फ्लशिंग के लिए एक अशक्त सूचक का उपयोग करता है।freopen()
स्ट्रीम के साथ "वर्तमान में संबद्ध" फ़ाइल को इंगित करने के लिए एक शून्य सूचक का उपयोग करता है।snprintf()
शून्य 'n' शून्य होने पर एक पॉइंटर पॉइंटर पास करने की अनुमति देता है।realloc()
एक नई वस्तु आवंटित करने के लिए एक शून्य सूचक का उपयोग करता है।free()
एक अशक्त सूचक पारित करने की अनुमति देता है।strtok()
बाद के कॉल के लिए एक शून्य सूचक का उपयोग करता है।यदि हम मामले को लेते हैं snprintf()
, तो यह समझ में आता है कि शून्य सूचक को पास करने की अनुमति तब होती है जब 'n' शून्य होता है, लेकिन यह अन्य (मानक पुस्तकालय) कार्यों के लिए ऐसा नहीं है जो समान शून्य 'n' की अनुमति देता है। उदाहरण के लिए: memcpy()
, memmove()
, strncpy()
, memset()
, memcmp()
।
यह न केवल मानक पुस्तकालय के परिचय में निर्दिष्ट है, बल्कि इन कार्यों के लिए एक बार फिर से प्रस्तुत है:
C99 §7.21.1 p2
/ C11 §7.24.1 p2
जहाँ
size_t
n के रूप में घोषित एक तर्क किसी फ़ंक्शन के लिए सरणी की लंबाई निर्दिष्ट करता है, n उस फ़ंक्शन के लिए कॉल पर मान शून्य हो सकता है। जब तक स्पष्ट रूप से अन्यथा इस उप-धारा में किसी विशेष कार्य के विवरण में कहा गया हो, ऐसे कॉल पर सूचक तर्क अभी भी मान्य मानों के रूप में 7.1.4 में वर्णित होंगे।
मुझे नहीं पता कि %p
एक अशक्त सूचक के साथ यूबी वास्तव में जानबूझकर है, लेकिन चूंकि मानक स्पष्ट रूप से बताता है कि अशक्त मान को मानक पुस्तकालय कार्यों के तर्क के रूप में अमान्य मान माना जाता है, और फिर यह स्पष्ट रूप से उन मामलों को निर्दिष्ट करता है जहां एक अशक्त है सूचक एक वैध तर्क (snprintf, नि: शुल्क, आदि) है, और फिर इसे चला जाता है और एक बार फिर से आवश्यकता को दोहराता तर्क शून्य में भी मान्य होने के लिए 'एन' मामलों में ( memcpy
, memmove
, memset
), तो मुझे लगता है कि यह मान लेना कि उचित है C मानक समिति ऐसी चीजों के अपरिभाषित होने से बहुत चिंतित नहीं है।
%p
करना अपरिभाषित व्यवहार नहीं है
सी स्टैंडर्ड के लेखकों ने किसी भी विशेष उद्देश्य के लिए उपयुक्त व्यवहार आवश्यकताओं को लागू करने के लिए पूरी तरह से सूची बनाने का कोई प्रयास नहीं किया। इसके बजाय, उन्हें उम्मीद थी कि कंपाइलर लिखने वाले लोग एक निश्चित मात्रा में सामान्य ज्ञान का प्रयोग करेंगे कि मानक को इसकी आवश्यकता है या नहीं।
इस सवाल का कि क्या यूबी कुछ बोलता है और शायद ही कभी उपयोगी होता है। महत्व के वास्तविक प्रश्न हैं:
क्या किसी को जो क्वालिटी कंपाइलर लिखने की कोशिश कर रहा है, उसे प्रेडिक्टेबल फैशन का व्यवहार करना चाहिए? वर्णित परिदृश्य के लिए उत्तर स्पष्ट रूप से हाँ है।
क्या प्रोग्रामर को यह उम्मीद करने का अधिकार होना चाहिए कि सामान्य प्लेटफार्मों के समान किसी भी चीज के लिए गुणवत्ता वाले कंपाइलर पूर्वानुमान योग्य फैशन में व्यवहार करेंगे? वर्णित परिदृश्य में, मैं कहूंगा कि इसका उत्तर हां है।
कुछ मोटे कंपाइलर लेखक मानक की व्याख्या को बढ़ा सकते हैं ताकि कुछ अजीब करने का औचित्य साबित हो सके? मैं उम्मीद नहीं करूंगा, लेकिन इसे खारिज नहीं करूंगा।
व्यवहार के बारे में संकलक स्क्वाक को सैनिटाइज करना चाहिए? यह उनके उपयोगकर्ताओं के व्यामोह स्तर पर निर्भर करेगा; एक संकलक संकलक शायद इस तरह के व्यवहार के बारे में स्क्वाकिंग करने के लिए डिफ़ॉल्ट नहीं होना चाहिए, लेकिन संभवत: ऐसा करने के लिए कॉन्फ़िगरेशन विकल्प प्रदान करता है जो कि "चतुर" / गूंगा संकलक के लिए पोर्ट किया जा सकता है जो अजीब व्यवहार करता है।
यदि मानक की एक उचित व्याख्या का अर्थ है कि एक व्यवहार परिभाषित किया गया है, लेकिन कुछ संकलक लेखक व्याख्या को अन्यथा करने के औचित्य को बढ़ाते हैं, तो क्या यह वास्तव में मायने रखता है कि मानक क्या कहता है?
printf("%p", (void*) 0)
मानक के अनुसार अपरिभाषित व्यवहार है या नहीं? गहरी नेस्टेड फ़ंक्शन कॉल चीन में चाय की कीमत के समान ही प्रासंगिक हैं। और हाँ, यूबी वास्तविक दुनिया के कार्यक्रमों में बहुत आम है - इसका क्या?
%p
के प्रत्येक संभावित अर्थ के बारे में सवाल का जवाब दिया ।