2008-09-16 12 views
55

निम्नलिखित कोड का टुकड़ा (सही) सी में सी में एक चेतावनी और त्रुटि देता ++ (का उपयोग कर जीसीसी & जी ++ क्रमश संस्करणों 3.4.5 और 4.2.1 के साथ परीक्षण किया; MSVC देखभाल करने के लिए प्रतीत नहीं होता है):मैं सी में 'char **' को 'const char * const *' में क्यों परिवर्तित नहीं कर सकता?

char **a; 
const char** b = a; 

मैं इसे समझ और स्वीकार कर सकता हूं।
इस समस्या का सी ++ समाधान बी को एक कॉन्स char * const * के रूप में बदलने के लिए है, जो पॉइंटर्स के पुन: असाइनमेंट को अस्वीकार करता है और आपको कॉन्स्ट-शुद्धता (C++ FAQ) को रोकने से रोकता है।

char **a; 
const char* const* b = a; 

हालांकि, शुद्ध सी में, सही संस्करण (स्थिरांक चार * स्थिरांक * का प्रयोग करके) अभी भी एक चेतावनी देता है, और मैं क्यों समझ में नहीं आता। क्या कलाकारों का उपयोग किये बिना इसे पाने का कोई तरीका है?

स्पष्टीकरण के लिए:
1) यह सी में चेतावनी क्यों उत्पन्न करता है? यह पूरी तरह से कॉन्स्ट-सुरक्षित होना चाहिए, और सी ++ कंपाइलर इसे इस तरह पहचानने लगता है।
2) इस char ** को पैरामीटर के रूप में स्वीकार करने के बारे में जाने का सही तरीका क्या है (और संकलक लागू करने के बाद) कि मैं वर्णों को संशोधित नहीं करूँगा? उदाहरण के लिए, अगर मैं एक समारोह लिखना चाहते थे:

void f(const char* const* in) { 
    // Only reads the data from in, does not write to it 
} 

और मैं, एक चार ** पर यह आह्वान क्या पैरामीटर के लिए सही प्रकार होगा करना चाहते थे?

संपादित करें: उन लोगों के लिए धन्यवाद जिन्होंने जवाब दिया है, विशेष रूप से जिन्होंने प्रश्नों को संबोधित किया और/या मेरे जवाबों का पालन किया।

मैंने जवाब स्वीकार कर लिया है कि मैं जो करना चाहता हूं उसे बिना किसी कलाकार के किया जा सकता है, भले ही यह संभव हो या नहीं।

+0

मैं आपके प्रश्न के रूप में उलझन में हूं, यह है: "मैं मुझे चेतावनी देने के लिए सी कैसे प्राप्त करूं?" या यह है "मैं एक संकलन त्रुटि फेंकने के लिए सी ++ कैसे प्राप्त करूं?" या शायद यह इनमें से कोई नहीं है। – user7116

+0

मैं छः पत्रिकाओं के साथ सहमत हूं, इस प्रश्न को और स्पष्टीकरण की आवश्यकता है। –

+0

सवाल यह है कि "मैं क्यों नहीं बदल सकता 'char **' to 'char * const *?" – Kevin

उत्तर

53

मुझे कुछ साल पहले भी यही समस्या थी और इससे मुझे कोई अंत नहीं हुआ।

सी में नियमों को अधिक सरलता से बताया गया है (यानी वे char** को const char*const* में परिवर्तित करने जैसे अपवादों की सूची नहीं देते हैं)। नतीजतन, यह सिर्फ अनुमति नहीं है। सी ++ मानक के साथ, इस तरह के मामलों की अनुमति देने के लिए उन्होंने अधिक नियम शामिल किए।

अंत में, यह सी मानक में केवल एक समस्या है। मुझे आशा है कि अगला मानक (या तकनीकी रिपोर्ट) इसे संबोधित करेगा।

+0

क्यों नीचे मतदान किया? कृपया समझाएँ! – Kevin

+0

मैंने निश्चित रूप से इसे वोट नहीं दिया; यह अब तक का सबसे प्रासंगिक उत्तर है। अगर मेरे पास 100 प्रतिष्ठा अंक थे तो मैं इसे वोट दूंगा। – HappyDude

+1

@ केविन: यदि आप अभी भी आसपास हैं, तो मैं सोच रहा हूं कि आप अपने उत्तर के बारे में कितने निश्चित हैं कि यह मानक में केवल एक समस्या है - उस समय आप वास्तव में मानक जांचने के लिए मानक के माध्यम से गए थे? यदि हां, तो मैं इस सवाल को बहुत करीब कर सकता हूं, क्योंकि यह उतना ही जवाब है जितना मैं प्राप्त करने जा रहा हूं। – HappyDude

11

> हालांकि, शुद्ध सी में, यह अभी भी एक चेतावनी देता है, और मुझे समझ नहीं आता क्यों

आप पहले से ही समस्या की पहचान की है - इस कोड स्थिरांक-सही नहीं है। "कॉन्स्ट सही" का अर्थ है कि, const_cast और C-style को छोड़कर कॉन्स को हटा दिया जाता है, आप उन कॉन्स्ट पॉइंटर्स या संदर्भों के माध्यम से कभी भी कॉन्स्ट ऑब्जेक्ट को संशोधित नहीं कर सकते हैं।

प्रोग्रामर त्रुटियों का पता लगाने के लिए, बड़े हिस्से में, कॉन्स्ट-शुद्धता का मूल्य है। यदि आप कुछ को कॉन्स्ट के रूप में घोषित करते हैं, तो आप यह कह रहे हैं कि आपको नहीं लगता कि इसे संशोधित किया जाना चाहिए - या कम से कम, जो कि कॉन्स्ट संस्करण तक पहुंच वाले हैं, उन्हें केवल इसे संशोधित करने में सक्षम नहीं होना चाहिए। पर विचार करें:

void foo(const int*); 

के रूप में घोषित कर दिया, foo संशोधित करने के लिए अनुमति पूर्णांक अपने तर्क द्वारा की ओर इशारा नहीं है।

क्यों कोड तुम्हें तैनात स्थिरांक-सही नहीं है यदि आप सुनिश्चित नहीं कर रहे हैं,, निम्नलिखित कोड पर विचार केवल थोड़ा HappyDude के कोड से अलग:

char *y; 

char **a = &y; // a points to y 
const char **b = a; // now b also points to y 

// const protection has been violated, because: 

const char x = 42; // x must never be modified 
*b = &x; // the type of *b is const char *, so set it 
     //  with &x which is const char* .. 
     //  .. so y is set to &x... oops; 
*y = 43; // y == &x... so attempting to modify const 
     //  variable. oops! undefined behavior! 
cout << x << endl; 

गैर स्थिरांक प्रकार केवल स्थिरांक को परिवर्तित कर सकते हैं एक स्पष्ट प्रकार के बिना डेटा-प्रकार पर 'कॉन्स्ट' के किसी भी छेड़छाड़ को रोकने के लिए विशेष तरीकों से प्रकार।

ऑब्जेक्ट्स शुरू में घोषित कॉन्स विशेष रूप से विशेष हैं - संकलक मान सकते हैं कि वे कभी नहीं बदलते हैं। हालांकि, अगर 'बी' को बिना किसी कलाकार के 'ए' के ​​मान को असाइन किया जा सकता है, तो आप अनजाने में एक कॉन्स्ट चर को संशोधित करने का प्रयास कर सकते हैं। इससे न केवल उस चेक को तोड़ दिया जाएगा जिसे आपने कंपाइलर से बनाने के लिए कहा था, जिससे कि वे वैरिएबल वैल्यू को बदलने से आपको अस्वीकार कर दिया जाए - यह आपको कंपाइलर ऑप्टिमाइज़ेशन को तोड़ने की अनुमति देगा!

कुछ कंपाइलरों पर, यह कुछ '43' पर '42' प्रिंट करेगा, और अन्य, प्रोग्राम क्रैश हो जाएगा।

संपादित-ऐड:

HappyDude: आपकी टिप्पणी स्थान पर है। या तो सी लैंगेज, या सी कंपाइलर जिसका आप उपयोग कर रहे हैं, सी ++ भाषा के मुकाबले कॉन्स char * const * मूल रूप से अलग तरीके से व्यवहार करता है। शायद इस स्रोत लाइन के लिए संकलक चेतावनी को शांत करने पर विचार करें।

संपादित-हटाएँ: हटाया टाइपो

+4

आपने जो कहा है वह सही है, लेकिन यह सवाल का समाधान नहीं करता है। जैसा कि मैंने कहा, मैं समझता हूं कि एक char ** से एक const char ** में कनवर्ट करना क्यों गलत है। जो मुझे समझ में नहीं आता है, क्यों एक char ** से एक कॉन्स char * const * में परिवर्तित करना गलत है। मैंने अपने प्रश्न को स्पष्ट करने के लिए अद्यतन किया है। – HappyDude

+3

यह दिलचस्प है कि यह प्रतिक्रिया मतदान हो रही है। मुझे लगता है कि बहुत से लोग प्रश्न की पहली जोड़ी रेखाओं को नहीं पढ़ते हैं, जो कुछ मैं भविष्य के लिए ध्यान में रखूंगा। हालांकि यह अपेक्षाकृत अस्पष्ट बिंदु पर काफी अच्छी तरह लिखित पोस्ट है, लेकिन मैं चाहता हूं कि यह प्रासंगिक था: पी। – HappyDude

+3

@Aaron: आपकी पोस्ट विषय के लिए विशेष रूप से प्रासंगिक नहीं है, लेकिन फिर भी अच्छी तरह लिखी गई है। – user7116

0

मैं जब परोक्ष चार कास्टिंग ** const करने के लिए एक त्रुटि प्राप्त करने में सक्षम नहीं हूँ चार * स्थिरांक *, कम से कम MSVC 14 (VS2k5) और जी ++ 3.3 पर। 3। जीसीसी 3.3.3 एक चेतावनी जारी करता है, जो मुझे बिल्कुल यकीन नहीं है कि यह करने में सही है या नहीं।

test.c: सी कोड के रूप में संकलन के साथ

#include <stdlib.h> 
#include <stdio.h> 
void foo(const char * const * bar) 
{ 
    printf("bar %s null\n", bar ? "is not" : "is"); 
} 

int main(int argc, char **argv) 
{ 
    char **x = NULL; 
    const char* const*y = x; 
    foo(x); 
    foo(y); 
    return 0; 
} 

आउटपुट: सीएल/टी.पी. /: सीएल/टीसी/W4/Wp64 test.c

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter 
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter 

सी ++ कोड के रूप में संकलन के साथ आउटपुट W4/Wp64 test.c

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter 
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter 

जीसीसी के साथ आउटपुट: जीसीसी -Wall test.c

012,351,
test2.c: In function `main': 
test2.c:11: warning: initialization from incompatible pointer type 
test2.c:12: warning: passing arg 1 of `foo' from incompatible pointer type 

जी के साथ ++ आउटपुट: जी ++ -Wall test.c

कोई उत्पादन

+0

क्षमा करें, मुझे यह स्पष्ट करना चाहिए था कि मैं जीसीसी के साथ संकलित हूं। मैंने इसे स्पष्ट करने के लिए अपना प्रश्न अपडेट किया है। सौभाग्य से (या शायद नहीं?) मैं शायद ही कभी एमएसवीसी में कई मुश्किल-से-हैंडल चेतावनियों में भाग लेता हूं। – HappyDude

+0

@HappyDude: मैंने जीसीसी से अपने निष्कर्षों के साथ अद्यतन किया है। और अब मैं देख रहा हूं कि आप क्या कह रहे हैं, लेकिन मैं अभी तक संकलक चेतावनी से सहमत नहीं हूं। मैं अपने सी विनिर्देश को तोड़ने जा रहा हूं और देखता हूं कि मुझे क्या मिल रहा है। – user7116

+0

@sixlettervariables: प्रतिक्रिया के लिए धन्यवाद! यदि आपको कुछ मिलता है तो मुझे बताएं, लेकिन मुझे संदेह है कि केविन ने जो कहा वह सही था और यह मानक द्वारा कवर नहीं किया गया है। – HappyDude

0

मैं बहुत यकीन है कि स्थिरांक कीवर्ड डेटा संकेत नहीं करता है बदला नहीं जा सकता हूँ/स्थिर है, केवल डेटा को केवल पढ़ने के लिए माना जाएगा। इस पर विचार करें:

const volatile int *const serial_port = SERIAL_PORT; 

जो वैध कोड है। अस्थिर और कांस्ट कैसे अस्तित्व में हो सकता है? सरल। अस्थिरता संकलक को डेटा का उपयोग करते समय स्मृति को हमेशा पढ़ने के लिए कहती है और सीरियल_पोर्ट पॉइंटर का उपयोग कर स्मृति को लिखने के प्रयास के दौरान संकलक को त्रुटि बनाने के लिए संकलक बताता है।

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

char *const p = (char *) 0xb000; 
//error: p = (char *) 0xc000; 
char **q = (char **)&p; 
*q = (char *)0xc000; // p is now 0xc000 

जब एक प्रयास स्मृति कि वास्तव में (उदाहरण के लिए रोम,) केवल पढ़ने के लिए लिखने के लिए किया जाता है तो क्या होता है शायद सब पर मानक में परिभाषित नहीं है।

+2

यह वास्तव में प्रश्न का समाधान नहीं करता है। जैसा कि मैं इसे समझता हूं, कास्टिंग के माध्यम से कॉन्स को हटाकर तकनीकी रूप से सी मानक के अनुसार एक अनिर्धारित ऑपरेशन है, भले ही अधिकांश कंपाइलर इसे अनुमति दें और 'सही काम करें'। लेकिन यह वही नहीं है जो मैं बिल्कुल पूछ रहा हूं। – HappyDude

+2

@HappyDude दूर कास्ट कास्टिंग अच्छी तरह से परिभाषित है। यह केवल अपरिभाषित होगा यदि आप वास्तव में 'const' (या अन्यथा अवांछनीय, जैसे एक स्ट्रिंग अक्षर) के रूप में घोषित वस्तु को लिखने का प्रयास करते हैं। –

9

संगत माना जाने के लिए, स्रोत सूचक तुरंत पूर्ववर्ती संकेत स्तर में होना चाहिए। तो, यह आप जीसीसी में चेतावनी दे देंगे:

char **a; 
const char* const* b = a; 

लेकिन यह ऐसा नहीं करेंगे:

const char **a; 
const char* const* b = a; 

वैकल्पिक रूप से, आप इसे डाली कर सकते हैं:

char **a; 
const char* const* b = (const char **)a; 

आप एक ही की आवश्यकता होगी जैसा कि आपने उल्लेख किया है फ़ंक्शन f() को आमंत्रित करने के लिए डाली गई है। जहां तक ​​मुझे पता है, इस मामले में एक अंतर्निहित रूपांतरण करने का कोई तरीका नहीं है (सी ++ को छोड़कर)।

+0

कृपया प्रश्न को और सावधानीपूर्वक पढ़ें। मुझे पता है कि पहला कोड स्निपेट गलत है, क्योंकि मैं तुरंत इसके बाद लाइन पर कहता हूं। दूसरा, हालांकि, ठीक होना चाहिए (जहां तक ​​मैं बता सकता हूं)। जैसा कि मैंने उल्लेख किया है, एमएसवीसी चेतावनी नहीं देता है, लेकिन जीसीसी करता है। – HappyDude

+0

क्षमा करें, मैंने जो भी चाहता था उसे अच्छी तरह से समझाया नहीं, और यह भी सुनिश्चित करने के लिए जीसीसी में परिणाम का परीक्षण नहीं किया कि कोड नमूने सटीक थे। ठीक करना। –

+0

धन्यवाद फैबियो, आपकी संपादित प्रतिक्रिया बहुत स्पष्ट है। मुझे लगता है कि मुझे अभी स्वीकार करना होगा कि मुझे इसे डालने की ज़रूरत है। – HappyDude

1

यह कष्टप्रद है, लेकिन अगर आप पुनर्निर्देशन का एक और स्तर जोड़ने के लिए तैयार हैं, तो आप अक्सर सूचक-टू-सूचक में नीचे पुश करने के लिए निम्न उपाय अपनाते हैं कर सकते हैं:

char c = 'c'; 
char *p = &c; 
char **a = &p; 

const char *bi = *a; 
const char * const * b = &bi; 

यह एक अलग है मतलब है, लेकिन यह आमतौर पर व्यावहारिक है, और यह एक कास्ट का उपयोग नहीं करता है।

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