2014-07-03 8 views
16

इस (कृत्रिम) उदाहरण पर विचार करें:'अस्थिर char [] `के रूप में परिभाषित स्ट्रिंग के लिए ओस्ट्रीम प्रिंट` 1` क्यों करता है?

#include <cstdio> 
#include <iostream> 

int main() { 
    volatile char test[] = "abc"; 
    std::printf("%s\n", test); 
    std::cout << test << "\n"; 
} 

जीसीसी और चल रहा है के साथ यह संकलन निम्नलिखित उत्पादन देता है:

$ g++ test.cc 
$ ./a.out 
abc 
1 

आप printf प्रिंट स्ट्रिंग सही ढंग से करते हुए cout प्रिंट 1 देख सकते हैं। इस मामले में पर 1 क्यों लिखता है?

+3

'अस्थिर चार [N]' 'मैचों बेहतर था bool' एन 'कॉन्स चार *'। असल में, यह बिल्कुल 'कॉन्स्ट char *' से मेल नहीं खाता है। – chris

+0

@ शार्थ महान पकड़, मैंने एक डुप्ली की तलाश भी नहीं की। वे काफी करीब हैं वे एक अच्छा विलय कर सकते हैं। –

उत्तर

14

operator<< की ही उपयुक्त अधिभार bool के लिए कि है, इसलिए सरणी bool में बदल जाती है (एक सूचक के माध्यम से), true देने के बाद से इसका पता गैर-शून्य है। यह 1 के रूप में आउटपुट करता है जब तक आप std::boolalpha मैनिपुलेटर का उपयोग नहीं करते।

यह const char * के लिए अधिभार उपयोग नहीं कर सकते उत्पादन स्ट्रिंग, या const void * के लिए है कि होगा जो जो होगा उत्पादन सूचक मूल्य, के बाद से ही वे रूपांतरण volatile क्वालीफायर को दूर करने की आवश्यकता होगी। लागू सूचक रूपांतरण क्वालीफायर जोड़ सकते हैं, लेकिन उन्हें हटा नहीं सकते हैं।

उत्पादन करने के लिए

स्ट्रिंग, आप क्वालीफायर दूर कास्ट करने के लिए होगा:

std::cout << const_cast<const char*>(test) << "\n"; 

लेकिन सावधान रहना है कि इस अपरिभाषित व्यवहार देता सरणी तक नहीं पहुंचा जाएगा के बाद से, जैसे कि वह अस्थिर नहीं थे।

printf कोई पुराना स्कूल विविधतापूर्ण कार्य नहीं है, जिससे कोई प्रकार की सुरक्षा नहीं मिलती है। %s विनिर्देशक इसे const char * के रूप में तर्क की व्याख्या करता है, जो भी वास्तव में है।

+2

क्या यह तकनीकी रूप से कानूनी है? क्या ऑपरेटर << 'धारणा को अनुकूलित कर सकता है कि स्ट्रिंग अस्थिर नहीं है? उदाहरण के लिए, यह तय करने के लिए 'स्ट्रेलन' हो सकता है कि बफर कितना बड़ा आवंटित किया जाए, फिर उस बफर पर प्रतिलिपि बनाने के लिए 'strcpy' का उपयोग करें। –

+2

जानवरों के उत्तरों में अपरिभाषित व्यवहार होता है: सी ++ 14 [dcl.type.cv] p6 कहता है "यदि एक अस्थिर-योग्य प्रकार के साथ परिभाषित ऑब्जेक्ट को संदर्भित करने के लिए एक गैर-गैर- अस्थिर-योग्य प्रकार, प्रोग्राम व्यवहार अपरिभाषित है। " आप आम तौर पर तत्वों पर हाथ से लिखित loops के माध्यम से अस्थिर सरणी के साथ बातचीत कर सकते हैं। –

+0

@ जेफरीयास्किन मैं इस बारे में सोच रहा था लेकिन इस मामले में 'const_cast' एक' prvalue' उत्पन्न करता है जहां तक ​​मैं कह सकता हूं लेकिन मैंने अभी तक विस्तार से नहीं सोचा है। –

5

std::basic_ostream::operator<< केवल const char* या const void* के लिए एक अधिभार जो इस मामले में मेल नहीं खाता, क्योंकि आप एक डाली बिना अस्थिर क्वालीफायर को छोड़ नहीं सकता, कृपया इस draft C++ standard अनुभाग 4.4योग्यता रूपांतरण जो कहते हैं में शामिल है:

प्रकार का एक prvalue "CV1 टी करने के लिए सूचक" प्रकार "CV2 टी करने के लिए सूचक" अगर "CV2 टी" अधिक सीवी योग्य की तुलना में "CV1 टी" है की एक prvalue में बदला जा सकता।

तो यह bool संस्करण का उपयोग कर रहा है और क्योंकि यह एक nullptr नहीं है परिणाम true है।

यदि आप अस्थिरtest से क्वालीफायर को हटाते हैं तो यह परिणाम आपको अपेक्षित प्रदान करेगा। कई उत्तरों अस्थिर क्वालीफायर को हटाने के लिए const_cast का उपयोग करने का सुझाव देते हैं लेकिन यह अपरिभाषित व्यवहार है। हम खंड 7.1.6.1के लिए जा रहा सीवी-क्वालिफायर पैरा द्वारा देख सकते हैं जो कहते हैं: एक प्रयास एक वस्तु एक के उपयोग के माध्यम से एक अस्थिर योग्य प्रकार से परिभाषित करने का उल्लेख किया जाता है

हैं गैर-अस्थिर-योग्य प्रकार के साथ glvalue, प्रोग्राम व्यवहार अपरिभाषित है।

const_cast इस मामले में एक prvalue पैदावार लेकिन यह है कि सूचक dereferencing एक lvalue जो अपरिभाषित व्यवहार लागू करेगा अर्जित करता है।

2

उत्तर वेब खोज का एक न्यूनतम राशि से here पाया:

लघु जवाब: coutvolatile क्वालीफायर की वजह से एक bool के रूप में वस्तु की व्याख्या कर रहा है। यह << ऑपरेटर के लिए ओवरलोडिंग का एक क्विर्क है।

लांग जवाब: एक अस्थिर सूचक, एक स्पष्ट कलाकारों के बिना एक गैर अस्थिर सूचक में परिवर्तित नहीं किया जा सकता है ताकि न char* है और न ही void* अधिभार जब << ऑपरेटर कहा जाता है के लिए इस्तेमाल किया जा सकता है। कोई अस्थिर योग्य अधिभार नहीं है, और निकटतम मैच bool अधिभार है, इस प्रकार आपके सरणी को पते या स्ट्रिंग के बजाए बूलियन मान के रूप में व्याख्या किया जाता है।

आप इसे कई तरीकों से ठीक कर सकते हैं, लेकिन कोई स्पष्ट डाली शायद है जैसे आप चाहते हैं: (। व्यक्तिगत तौर पर मैं const char* लिए डाली हैं)

std::cout<< (char*)test <<std::endl; 

0

यह volatile क्वालीफायर है कि एक bool करने के लिए इसे डाले, ऐसा करें:

std::cout << const_cast<char*>(test) << "\n"; 
+0

इस उत्तर में अपरिभाषित व्यवहार है: C++ 14 [dcl.type।सीवी] पी 6 कहता है "अगर एक अस्थिर-योग्य प्रकार के साथ एक अस्थिर-योग्य प्रकार के साथ परिभाषित ऑब्जेक्ट को संदर्भित करने के लिए एक गैर-अस्थिर-योग्य प्रकार वाले ग्लैवल्यू के उपयोग के माध्यम से प्रयास किया जाता है, तो प्रोग्राम व्यवहार अपरिभाषित होता है।" –

+0

@ जेफरीयस्किन वैरिएबल का अनुमान लगाता है ... 'अस्थिर '! ;) –

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

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