इस त्रुटि का क्या अर्थ है? मैं इसे किसी भी तरह से हल नहीं कर सकता।
चेतावनी: स्ट्रिंग निरंतर से 'char *' में रूपांतरण
इस त्रुटि का क्या अर्थ है? मैं इसे किसी भी तरह से हल नहीं कर सकता।
चेतावनी: स्ट्रिंग निरंतर से 'char *' में रूपांतरण
जवाबों:
जैसा कि मेरा अभ्यस्त है, मैं इस त्रुटि के whys और जहां कहीं भी पृष्ठभूमि तकनीकी जानकारी का एक सा प्रदान करने जा रहा हूँ।
मैं C स्ट्रिंग्स को इनिशियलाइज़ करने के चार अलग-अलग तरीकों का निरीक्षण करने जा रहा हूँ और देखता हूँ कि उनके बीच क्या अंतर हैं। ये चार तरीके हैं:
char *text = "This is some text";
char text[] = "This is some text";
const char *text = "This is some text";
const char text[] = "This is some text";
अब इसके लिए मैं तीसरे अक्षर "i" को "o" में बदलकर "Thos is some text" बनाना चाहता हूं। वह, सभी मामलों में (आप सोचेंगे), द्वारा प्राप्त किया जा सकता है:
text[2] = 'o';
अब आइए देखें कि स्ट्रिंग घोषित करने का प्रत्येक तरीका क्या करता है और यह text[2] = 'o';
कथन किस प्रकार चीजों को प्रभावित करेगा।
सबसे पहले देखा जाने वाला तरीका char *text = "This is some text";
:। इसका शाब्दिक अर्थ क्या है? खैर, सी में, इसका शाब्दिक अर्थ है "एक चर बनाएं text
जो इस स्ट्रिंग शाब्दिक के लिए एक रीड-राइट पॉइंटर है जो रीड-ओनली (कोड) स्पेस में आयोजित किया जाता है।" यदि आपके पास विकल्प -Wwrite-strings
चालू है तो आपको एक चेतावनी मिलती है जैसा कि ऊपर दिए गए प्रश्न में देखा गया है।
मूल रूप से इसका मतलब है कि "चेतावनी: आपने एक ऐसा चर बनाने की कोशिश की है जो आपके द्वारा लिखे गए क्षेत्र में पढ़ने-लिखने के बिंदु पर नहीं है"। यदि आप कोशिश करते हैं और फिर तीसरे चरित्र को "ओ" पर सेट करते हैं, तो आप वास्तव में केवल पढ़ने के लिए लिखने की कोशिश कर रहे हैं और चीजें अच्छी नहीं होंगी। लिनक्स के साथ एक पारंपरिक पीसी पर जिसके परिणामस्वरूप:
विभाजन दोष
अब दूसरा वाला char text[] = "This is some text";
:। शाब्दिक रूप से, C में, इसका मतलब है कि "एक प्रकार का वर्ण बनाएं" char "और इसे डेटा के साथ प्रारंभ करें" यह कुछ है \ 0 "। सरणी का आकार डेटा को संग्रहीत करने के लिए पर्याप्त बड़ा होगा"। ताकि वास्तव में RAM आवंटित हो जाए और रनटाइम पर "यह कुछ टेक्स्ट \ 0" है। कोई चेतावनी, कोई त्रुटि नहीं, पूरी तरह से वैध। और अगर आप डेटा को संपादित करने में सक्षम होना चाहते हैं तो इसे करने का सही तरीका है । आइए कमांड चलाने की कोशिश करें text[2] = 'o'
:
थोस कुछ पाठ है
यह काम किया, पूरी तरह से। अच्छा।
अब तीसरा तरीका const char *text = "This is some text";
:। फिर शाब्दिक अर्थ: पाठ "है कि एक" एक चर बुलाया बनाएँ " केवल पढ़ने के लिए । केवल पढ़ने के लिए स्मृति में इस डेटा के लिए सूचक"। ध्यान दें कि सूचक और डेटा दोनों अब केवल-पढ़ने के लिए हैं। कोई त्रुटि नहीं, कोई चेतावनी नहीं। यदि हम अपना परीक्षण कमांड चलाते हैं और चलाते हैं तो क्या होता है? खैर, हम नहीं कर सकते। कंपाइलर अब बुद्धिमान है और जानता है कि हम कुछ बुरा करने की कोशिश कर रहे हैं:
त्रुटि: केवल-पढ़ने के लिए स्थान '* (पाठ + 2u)'
यह भी संकलन नहीं होगा। केवल पढ़ने के लिए लिखने की कोशिश करने वाली मेमोरी अब संरक्षित है क्योंकि हमने कंपाइलर को बताया है कि हमारा पॉइंटर केवल-पढ़ने के लिए मेमोरी है। बेशक, इसे केवल-पढ़ने वाली मेमोरी की ओर इंगित करने की आवश्यकता नहीं है , लेकिन यदि आप इसे पढ़ने-लिखने वाली मेमोरी (रैम) की ओर इंगित करते हैं, तो मेमोरी को कंपाइलर द्वारा लिखे जाने से भी संरक्षित किया जाएगा।
अंत में अंतिम रूप const char text[] = "This is some text";
:। दोबारा, जैसे पहले इसके साथ []
रैम में एक सरणी आवंटित करता है और इसमें डेटा को कॉपी करता है। हालाँकि, अब यह केवल-पढ़ने के लिए एक सरणी है। आप इसे नहीं लिख सकते क्योंकि इसके लिए सूचक को टैग किया गया है const
। इसे लिखने का प्रयास करने का परिणाम है:
त्रुटि: केवल-पढ़ने के लिए स्थान '* (पाठ + 2u)'
तो, हम कहाँ हैं का एक त्वरित सारांश:
यह फ़ॉर्म पूरी तरह से अमान्य है और इसे हर कीमत पर टाला जाना चाहिए। यह सभी प्रकार की बुरी चीजों के लिए दरवाजा खोलता है:
char *text = "This is some text";
यदि आप डेटा को संपादन योग्य बनाना चाहते हैं तो यह फ़ॉर्म सही फ़ॉर्म है:
char text[] = "This is some text";
यदि आप ऐसे तार चाहते हैं जो संपादित नहीं किए जाएंगे, तो यह फ़ॉर्म सही रूप है:
const char *text = "This is some text";
यह फ़ॉर्म रैम के लिए बेकार है लेकिन इसके उपयोग हैं। हालांकि यह अभी के लिए भूल जाओ।
const char text[] = "This is some text";
PROGMEM
, PSTR()
या F()
। इस प्रकार, की const char text[]
तुलना में अधिक रैम का उपयोग नहीं करता है const char *text
।
(const char *)(...)
कास्टिंग के रूप में परिभाषित करते हैं । कोई वास्तविक प्रभाव यदि बोर्ड को इसकी आवश्यकता नहीं है, लेकिन एक बड़ी बचत यदि आप अपने कोड को एक बोर्ड पर पोर्ट करते हैं जो करता है।
मैकेंको के उत्कृष्ट जवाब पर विस्तार से बताने के लिए, एक अच्छा कारण है कि कंपाइलर आपको इस बारे में चेतावनी देता है। चलो एक परीक्षण स्केच बनाते हैं:
char *foo = "This is some text";
char *bar = "This is some text";
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo [2] = 'o'; // change foo only
Serial.println (foo);
Serial.println (bar);
} // end of setup
void loop ()
{
} // end of loop
हमारे यहां दो वेरिएबल्स हैं, फू और बार। मैं सेटअप में उनमें से एक को संशोधित करता हूं (), लेकिन देखें कि परिणाम क्या है:
Thos is some text
Thos is some text
वे दोनों बदल गए!
वास्तव में अगर हम चेतावनियों को देखते हैं:
sketch_jul14b.ino:1: warning: deprecated conversion from string constant to ‘char*’
sketch_jul14b.ino:2: warning: deprecated conversion from string constant to ‘char*’
संकलक जानता है कि यह डोडी है, और यह सही है! इसका कारण यह है, कि संकलक (यथोचित) को उम्मीद है कि स्ट्रिंग स्थिरांक नहीं बदलते (क्योंकि वे स्थिरांक हैं)। इस प्रकार यदि आप "This is some text"
अपने कोड में स्ट्रिंग को लगातार कई बार संदर्भित करते हैं तो उन सभी को समान मेमोरी आवंटित करने की अनुमति है । अब यदि आप एक को संशोधित करते हैं, तो आप उन सभी को संशोधित करते हैं!
*foo
और *bar
उपयोग करना , ऐसा होने से रोक सकता है? इसके अलावा, यह कैसे किसी भी तार डाल नहीं से अलग है, जैसे :? char *foo;
new
, strcpy
और delete
)।
या तो एक स्ट्रिंग स्थिरांक को पास करने की कोशिश करना बंद कर दें जहां कोई फ़ंक्शन एक फ़ंक्शन लेता है char*
, या फ़ंक्शन को बदलता है ताकि यह const char*
बदले में ले जाए ।
स्ट्रिंग "यादृच्छिक स्ट्रिंग" की तरह हैं।
उदाहरण:
void foo (char * s)
{
Serial.println (s);
}
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo ("bar");
} // end of setup
void loop ()
{
} // end of loop
चेतावनी:
sketch_jul14b.ino: In function ‘void setup()’:
sketch_jul14b.ino:10: warning: deprecated conversion from string constant to ‘char*’
फ़ंक्शन foo
एक चार * की उम्मीद करता है (जो इसे संशोधित कर सकता है) लेकिन आप एक स्ट्रिंग शाब्दिक पारित कर रहे हैं, जिसे संशोधित नहीं किया जाना चाहिए।
संकलक आपको ऐसा नहीं करने की चेतावनी दे रहा है। पदावनत होने के नाते यह चेतावनी से भविष्य के संकलक संस्करण में एक त्रुटि में बदल सकता है।
समाधान: बनाओ फू ले एक कास्ट चार *:
void foo (const char * s)
{
Serial.println (s);
}
मुझे नहीं मिला। क्या आपका मतलब संशोधित नहीं किया जा सकता है?
C (और C ++) के पुराने संस्करण आपको ऊपर दिए गए मेरे उदाहरण की तरह कोड लिखते हैं। आप एक फ़ंक्शन (जैसे foo
) बना सकते हैं, जो आपके द्वारा नीचे जाने वाली किसी चीज़ को प्रिंट करता है, और फिर एक शाब्दिक स्ट्रिंग (उदाहरण के लिए foo ("Hi there!");
) को पास करता है ।
हालाँकि, एक फ़ंक्शन जो char *
एक तर्क के रूप में लेता है, उसे अपने तर्क को संशोधित करने की अनुमति है (यानी Hi there!
इस मामले में संशोधित करें)।
आपने लिखा हो सकता है, उदाहरण के लिए:
void foo (char * s)
{
Serial.println (s);
strcpy (s, "Goodbye");
}
दुर्भाग्य से, एक शाब्दिक नीचे पारित करके, आपने अब उस शाब्दिक रूप से संशोधित किया है ताकि "हाय वहाँ!" अब "अलविदा" है जो अच्छा नहीं है। वास्तव में यदि आप एक लंबी स्ट्रिंग में कॉपी करते हैं, तो आप अन्य चर को अधिलेखित कर सकते हैं। या, कुछ कार्यान्वयनों पर आपको एक एक्सेस उल्लंघन मिलेगा क्योंकि "हाय वहाँ!" शायद केवल पढ़ने के लिए (संरक्षित) रैम में रखा गया है।
इसलिए संकलक-लेखक धीरे-धीरे इस उपयोग को चित्रित कर रहे हैं , ताकि जिन कार्यों से आप शाब्दिक रूप से गुजरते हैं, उन्हें इस तर्क के रूप में घोषित करना चाहिए const
।
can not
संशोधित है?
मेरे पास यह संकलन त्रुटि है:
TimeSerial.ino:68:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
if(Serial.find(TIME_HEADER)) {
^
कृपया इस पंक्ति को बदलें:
#define TIME_HEADER "T" // Header tag for serial time sync message
इस लाइन के साथ:
#define TIME_HEADER 'T' // Header tag for serial time sync message
और संकलन अच्छी तरह से चला जाता है।