2012-01-12 22 views
17

सी ++ के विपरीत, सी const_cast की कोई धारणा नहीं है।एक संघ अपरिभाषित व्यवहार के माध्यम से कास्टिंग-कास्टिंग है?

void const * p; 
void * q = p; // not good 

सबसे पहले: है इस कलाकारों वास्तव में अपरिभाषित व्यवहार है कि वहाँ एक अयोग्य सूचक के लिए एक स्थिरांक योग्य सूचक कन्वर्ट करने के लिए कोई वैध तरीका है, है?

किसी भी घटना में, जीसीसी इस बारे में चेतावनी देता है। "साफ" कोड बनाने के लिए जिसके लिए एक कॉन्स-कास्ट की आवश्यकता होती है (यानी जहां मैं गारंटी दे सकता हूं कि मैं सामग्री को म्यूटेट नहीं करूँगा, लेकिन मेरे पास सब कुछ एक परिवर्तनीय सूचक है), मैंने निम्नलिखित "रूपांतरण" चाल देखी है:

typedef union constcaster_ 
{ 
    void * mp; 
    void const * cp; 
} constcaster; 

उपयोग: u.cp = p; q = u.mp;

ऐसे संघ के माध्यम से दूरसंचार को दूर करने के लिए सी भाषा नियम क्या हैं? सी का मेरा ज्ञान केवल बहुत ही कमजोर है, लेकिन मैंने सुना है कि सी सी ++ की तुलना में संघ पहुंच के बारे में अधिक स्पष्ट है, इसलिए जब मुझे इस निर्माण के बारे में बुरा लगा है, तो मुझे मानक से एक तर्क चाहिए (सी 99 मुझे लगता है, हालांकि अगर यह सी 11 में बदल गया है तो यह जानना अच्छा होगा)।

+1

आप 'शून्य * q = (शून्य *) p' में पहली कोड ब्लॉक मतलब है? – kennytm

+0

@ केनीटीएम: हाँ - क्या मुझे स्पष्ट कलाकारों की आवश्यकता है, और/या इससे कोई फर्क पड़ता है? –

+0

अंतर्निहित कास्ट जीसीसी के बिना क्वालीफायरों को हटाने के बारे में चेतावनी दी गई है। लेकिन जीसीसी अभी भी एक त्रुटि रिपोर्ट करता है ("प्रारंभकर्ता तत्व निरंतर नहीं है") कास्ट के साथ भी। –

उत्तर

10

यह कार्यान्वयन परिभाषित किया है, C99 6.5.2.3/5 देखें:

अगर एक संघ वस्तु के एक सदस्य का मान प्रयोग किया जाता है जब सबसे वस्तु के लिए हाल ही में दुकान एक अलग सदस्य के लिए किया गया था, व्यवहार कार्यान्वयन-परिभाषित है।

अद्यतन: @AaronMcDaid टिप्पणी की कि यह सब के बाद अच्छी तरह से परिभाषित किया जा सकता है।

मानक निर्दिष्ट 6.2.5/27 के बाद:

इसी तरह, संगत प्रकार के योग्य या अयोग्य संस्करणों की ओर इशारा ही प्रतिनिधित्व और संरेखण requirements.27)

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

और (6.7.2.1/14):

एक संघ वस्तु, उपयुक्त रूप से परिवर्तित करने के लिए एक सूचक है अपने सदस्यों में से प्रत्येक के लिए अंक (या अगर एक सदस्य एक bitfield है, तो करने के लिए इकाई जिसमें रहता है), और इसके विपरीत।

एक पराक्रम निष्कर्ष है कि इस विशेष मामले में , वहाँ संघ में तत्वों का उपयोग करने की बिल्कुल एक ही रास्ता के लिए ही कमरा है।

+2

+1 :) – Kos

+1

अच्छा! तो मुझे गारंटी नहीं है कि यह वास्तव में मुझे क्या लगता है? –

+1

खैर, "कार्यान्वयन परिभाषित" का अर्थ है कि संकलक प्रदाता को यह निर्दिष्ट करना होगा कि क्या होता है। हालांकि, आप * सभी * कंपाइलर्स के लिए काम करने पर भरोसा नहीं कर सकते हैं। – Lindydancer

3

मेरी समझ यह है कि यूबी केवल तब उत्पन्न हो सकता है जब आप कॉन्स्ट-घोषित ऑब्जेक्ट को संशोधित करने का प्रयास करते हैं।

तो निम्न कोड यूबी नहीं है:

int x = 0; 
const int *cp = &x; 
int *p = (int*)cp; 
*p = 1; /* OK: x is not a const object */ 

लेकिन इस यूबी है:

const int cx = 0; 
const int *cp = &cx; 
int *p = (int*)cp; 
*p = 1; /* UB: cx is const */ 

एक डाली के बजाय एक संघ के उपयोग यहाँ कोई फर्क नहीं करना चाहिए।

C99 चश्मा से (6.7.3 प्रकार क्वालिफायर):

एक प्रयास गैर स्थिरांक-योग्य के साथ एक lvalue के उपयोग के माध्यम से एक वस्तु एक स्थिरांक योग्य प्रकार से परिभाषित संशोधित करने के लिए किया जाता है प्रकार, व्यवहार अपरिभाषित है।

+1

आप मान सकते हैं कि मैंने कभी भी कुछ भी नहीं बदला है। यही है, मेरे पास एक गैर-उत्परिवर्तनीय ऑपरेशन है जिसे विरासत उत्परिवर्तनीय सूचक से निपटने की आवश्यकता है। मैं समझता हूं कि स्थिरता का उल्लंघन यूबी है - मेरा प्रश्न मुख्य रूप से सूचक जुगलिंग के बारे में है। सी ++ में मैं बस 'शून्य * q = const_cast (पी); '... –

+0

@KerrekSB' const_cast '' (शून्य *) 'के लिए सिंटैक्टिक चीनी नहीं है (शायद कुछ अतिरिक्त चेक के साथ लेकिन वही व्यवहार)? –

+2

@ क्रिस्टियन राउ: नहीं, यह भाषा का हिस्सा है, और टाइप सिस्टम। यदि आप करेंगे, तो संपूर्ण प्रकार की प्रणाली असेंबलर पर सिंटैक्टिक चीनी है, इसलिए भेद यहां महत्वपूर्ण है ... –

0

इसे बिल्कुल मत डालो। यह कॉन्स के लिए एक सूचक है जिसका अर्थ है कि डेटा को संशोधित करने का प्रयास करने की अनुमति नहीं है और कई कार्यान्वयन में प्रोग्राम को क्रैश होने का कारण बन जाएगा यदि पॉइंटर अपरिवर्तनीय स्मृति को इंगित करता है। यहां तक ​​कि यदि आपको पता है कि स्मृति को संशोधित किया जा सकता है, तो इसके लिए अन्य पॉइंटर्स भी हो सकते हैं जो इसे बदलने की उम्मीद नहीं करते हैं उदा। अगर यह एक तर्कसंगत अपरिवर्तनीय स्ट्रिंग के भंडारण का हिस्सा है।

चेतावनी अच्छे कारण के लिए है।

यदि आपको किसी कॉन्स्ट पॉइंटर की सामग्री को संशोधित करने की आवश्यकता है, तो ऐसा करने के लिए पोर्टेबल सुरक्षित तरीका यह है कि वह उस स्मृति को कॉपी करने के लिए सबसे पहले है और फिर उसे संशोधित करें।

+0

उनकी टिप्पणियों से मुझे लगता है कि वह इन प्रभावों से अवगत हैं और इसे विरासत समारोह में पास करना चाहते हैं, एक गैर-कॉन्स्ट पॉइंटर स्वीकार करना और डेटा को संशोधित नहीं करना चाहते हैं (जो भी कारण पहले स्थान पर गैर-कॉन्स लेना चाहते थे)। और वैसे, वास्तविक सवाल का क्या जवाब है? –

+0

@ क्रिस्टियन राउ: यदि आप जानते हैं कि लैगसी फ़ंक्शन डेटा को संशोधित नहीं करता है, तो मूल प्रश्न पर केनीटीएम की टिप्पणी में एक स्पष्ट कलाकार ठीक होगा। – JeremyP

+1

@ केरेक एसबी सी आपको एक कॉन्स पैरामीटर में एक गैर कॉन्स पॉइंटर पास करने की अनुमति देता है। 'कॉन्स char * पी = क्यू; 'जहां क्यू char * ठीक है। – JeremyP

3

प्रारंभिकरण निश्चित रूप से यूबी का कारण नहीं बनता है। योग्य सूचक प्रकारों के बीच रूपांतरण को §6.3.2.3/2 (n1570 (C11)) में स्पष्ट रूप से अनुमति दी गई है। यह उस पॉइंटर में सामग्री का उपयोग है जिसके बाद यूबी (@rodrigo का उत्तर देखें)।

हालांकि, आपको void* को const void* में बदलने के लिए एक स्पष्ट कलाकार की आवश्यकता है, क्योंकि सरल असाइनमेंट की बाधा को अभी भी एलएचएस पर आरएचएस पर दिखाई देने वाले सभी क्वालीफायर की आवश्यकता होती है।

§6.7.9/11: ... वस्तु का प्रारंभिक मूल्य अभिव्यक्ति (रूपांतरण के बाद) का होता है; सरल असाइनमेंट के लिए समान प्रकार की बाधाएं और रूपांतरण लागू होते हैं, स्केलर के प्रकार को घोषित प्रकार के अयोग्य संस्करण के रूप में लेते हैं।

§6.5.16.1/1: (सरल असाइनमेंट/contraints)

  • ... दोनों ऑपरेंड संगत प्रकार के योग्य या अयोग्य संस्करण के लिए संकेत दिए गए हैं, और प्रकार के आधार पर करने के लिए बताया बाईं ओर दाईं ओर इंगित प्रकार के सभी क्वालीफायर हैं;
  • ... एक ऑपरेंड एक ऑब्जेक्ट प्रकार के लिए एक सूचक है, और दूसरा void के योग्य या अयोग्य संस्करण के लिए सूचक है, और बाईं ओर इंगित प्रकार के प्रकार के सभी क्वालीफायर हैं दाईं ओर ;

मुझे नहीं पता कि जीसीसी हालांकि चेतावनी क्यों देता है।


और यूनियन चाल के लिए, हाँ यह यूबी नहीं है, लेकिन फिर भी परिणाम शायद अनिर्दिष्ट है।

§6.5.2.3/3 fn 95: सदस्य एक संघ ऑब्जेक्ट की सामग्री को पढ़ने के लिए उपयोग किया है के रूप में सदस्य पिछले, के उचित भाग वस्तु में एक मूल्य के स्टोर करने के लिए इस्तेमाल किया ही नहीं है मूल्य के ऑब्जेक्ट प्रस्तुति को 6.2.6 में वर्णित नए प्रकार में ऑब्जेक्ट प्रस्तुति के रूप में पुन: परिभाषित किया गया है (एक प्रक्रिया जिसे कभी-कभी "टाइप पनिंग" कहा जाता है)। यह एक जाल प्रतिनिधित्व हो सकता है।

§6.2.6.1/7: जब एक मूल्य के संघ प्रकार का ऑब्जेक्ट के एक सदस्य में संग्रहित है, वस्तु प्रतिनिधित्व के बाइट्स है कि उस सदस्य के अनुरूप नहीं है, लेकिन अन्य सदस्यों के अनुरूप है अनिर्दिष्ट मान लेना । (* ध्यान दें: एक अपवाद के लिए यह भी देखना §6.5.2.3/6, लेकिन यह यहाँ लागू नहीं होता) n1124 में


इसी वर्गों (C99)

  • C11 § हैं 6.3.2.3/2 = C99 §6.3.2.3/2
  • C11 §6.7.9/11 = C99 §6.7.8/11
  • C11 §6.5.16.1/1 = C99 §6.5.16.1/1
  • सी 11 §6.5.2.3/3 एफएन 95 = गायब ("टाइपिंग पनिंग" मैं प्रकट नहीं होता n C99)
  • C11 §6.2.6.1/7 = C99 §6.2.6.1/7
+0

ग्रेट, धन्यवाद! तो क्या आपको लगता है कि सी कोड लिखने का सबसे अच्छा तरीका है जब आवश्यक हो तो एक स्पष्ट कलाकार होना चाहिए और जीसीसी को '-नो-कास्ट-क्वालिटी' पास करना है? –

+0

@ केरेकस्क: मैं निश्चित रूप से अंतर्निहित जानवरों पर कठोर चेतावनियों का पक्ष लेता हूं जो भविष्य में समस्या का कारण बन सकता है, और शायद उस क्षेत्र को कम करने के लिए '#pragma जीसीसी डायग्नोस्टिक' का उपयोग करना बेहतर है जहां चेतावनी अक्षम है। – kennytm

+0

भले ही यह सबसे अच्छा जवाब है, क्या आप मेरे निचले प्रतिनिधि उत्तर को स्वीकार करने का समर्थन करेंगे? यह प्रतिष्ठा-प्रेरणा-उपयोगिता के बारे में है, आप देखते हैं :-) –

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