স্ট্রিং ধ্রুবক থেকে 'চর *' এ রূপান্তর বাতিল করা হয়েছে


16

এই ত্রুটির অর্থ কী? আমি এটি কোনওভাবেই সমাধান করতে পারি না।

সতর্কতা: স্ট্রিং ধ্রুবক থেকে 'চর *' এ রূপান্তরকরণ [-Wwrit-तार]]


এই প্রশ্নটি স্ট্রোভারফ্লোতে হওয়া উচিত, আরডিনো নয় :)
বিজয় চাভদা

উত্তর:


26

আমার অভ্যাস হিসাবে, আমি এই ত্রুটিটির কারণগুলি এবং এর কারণগুলির মধ্যে কিছুটা পটভূমি প্রযুক্তিগত তথ্য সরবরাহ করতে যাচ্ছি।

আমি সি স্ট্রিংগুলি সূচনা করার চারটি ভিন্ন উপায়ে পরিদর্শন করতে যাচ্ছি এবং তাদের মধ্যে পার্থক্য কী তা দেখুন। এই চারটি প্রশ্নে উপায়:

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" কে একটি "ও" তে পরিণত করতে চাই "এটিকে কিছু পাঠ্য"। যা, সব ক্ষেত্রেই (আপনি ভাবতেন), অর্জন করতে পারে:

text[2] = 'o';

এবার আসুন স্ট্রিং ঘোষণার প্রতিটি উপায় কী করে এবং সেই text[2] = 'o';বিবৃতিটি কীভাবে প্রভাব ফেলবে তা দেখুন at

প্রথম সবচেয়ে বেশি দেখা গেছে পথ: char *text = "This is some text";। এর আক্ষরিক অর্থ কী? ঠিক আছে, সিতে এর আক্ষরিক অর্থ "একটি পরিবর্তনশীল বলা হয় textযা এই স্ট্রিংটির আধ্যাত্মিক পঠনযোগ্য যা কেবল পঠনযোগ্য (কোড) স্পেসে রাখা হয়"। আপনি যদি বিকল্পটি -Wwrite-stringsচালু করে থাকেন তবে উপরের প্রশ্নে দেখা হিসাবে আপনি একটি সতর্কতা পান।

মূলত এর অর্থ "সতর্কতা: আপনি এমন একটি ভেরিয়েবল তৈরি করার চেষ্টা করেছেন যা আপনি যে অঞ্চলে লিখতে পারবেন না সেটিতে পঠন-লেখার পয়েন্ট"। আপনি যদি চেষ্টা করেন এবং তারপরে তৃতীয় অক্ষরটিকে "ও" তে সেট করেন তবে আপনি বাস্তবে কেবলমাত্র পঠনযোগ্য অঞ্চলে লেখার চেষ্টা করছেন এবং জিনিসগুলি সুন্দর হবে না। লিনাক্স সহ একটি traditionalতিহ্যবাহী পিসিতে যার ফলাফল:

বিভাজন ফল্ট

এখন দ্বিতীয় এক: char text[] = "This is some text";। আক্ষরিক অর্থে সি তে এর অর্থ হল "চর" টাইপের একটি অ্যারে তৈরি করুন এবং ডেটা দিয়ে এটি সূচনা করুন "এটি কিছু পাঠ্য \ 0"। অ্যারেটির আকার ডেটা সংরক্ষণ করার জন্য যথেষ্ট বড় হবে "। সুতরাং এটি আসলে র‍্যাম বরাদ্দ করে এবং রানটাইমের সময় "এটি কিছু পাঠ্য \ 0" এর অনুলিপি করে। কোনও সতর্কতা নেই, কোনও ত্রুটি নেই, পুরোপুরি বৈধ। আপনি যদি ডেটা সম্পাদনা করতে সক্ষম হতে চান তবে তা করার সঠিক উপায় । কমান্ডটি চালানোর চেষ্টা করুন text[2] = 'o':

আপনার কিছু পাঠ্য

এটা পুরোপুরি কাজ করেছে। ভাল.

এখন তৃতীয় উপায়: const char *text = "This is some text";। আবার আক্ষরিক অর্থ: "পাঠ্য" নামক একটি ভেরিয়েবল তৈরি করুন যা কেবলমাত্র পঠন মেমরিতে এই ডেটাতে পঠিত পয়েন্টার। " নোট করুন যে পয়েন্টার এবং ডেটা উভয়ই কেবল পঠনযোগ্য। কোনও ত্রুটি নেই, কোনও সতর্কতা নেই। যদি আমরা আমাদের পরীক্ষা কমান্ডটি চেষ্টা করে চালিত করি তবে কী হবে? ভাল, আমরা পারি না। সংকলকটি এখন বুদ্ধিমান এবং জানে যে আমরা খারাপ কিছু করার চেষ্টা করছি:

ত্রুটি: কেবলমাত্র পঠনযোগ্য অবস্থান '* (পাঠ্য + 2u)' এর অ্যাসাইনমেন্ট

এটি সংকলনও করবে না। কেবল পঠনযোগ্য মেমরিটিতে লেখার চেষ্টা করা এখন সুরক্ষিত কারণ আমরা সংকলককে বলেছি যে আমাদের পয়েন্টারটি কেবল পঠনযোগ্য মেমরি to অবশ্যই, এটা না আছে -অনলি মেমরি প্রতি নির্দেশ করা হবে, কিন্তু আপনি তা বাতলান পাঠযোগ্য লিখতে মেমরি (RAM) মেমরি এখনও কম্পাইলার দ্বারা লেখা হওয়া থেকে সুরক্ষিত হবে।

অবশেষে গত ফর্ম: 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";

6
উল্লেখ্য যে, Arduinos (অন্তত এভিআর ভিত্তিক বেশী) উপর, স্ট্রিং লিটারেল, র্যাম বাস যদি না আপনি তাদের মত একটি ম্যাক্রো সঙ্গে ঘোষণা মূল্য PROGMEM, PSTR()অথবা F()। সুতরাং, এর const char text[]চেয়ে বেশি র‌্যাম ব্যবহার করে না const char *text
এডগার বোনেট

টেন্যাসিডিনো এবং আরও অনেক সাম্প্রতিক আরডুইনো-সামঞ্জস্যযোগ্য কোডগুলি স্বয়ংক্রিয়ভাবে স্ট্রিং লিটারেল স্থাপন করে, তাই আপনার বোর্ডে F () প্রয়োজন কিনা তা পরীক্ষা করে দেখার মতো worth
ক্রেগ.ফিড

@ ক্রেগ.ফিড সাধারণভাবে F () নির্বিশেষে ব্যবহার করা উচিত। যাদের "প্রয়োজন" হয় না তারা এটিকে একটি সাধারণ (const char *)(...)ing ালাই হিসাবে সংজ্ঞায়িত করে to বোর্ডের প্রয়োজন না থাকলে কোনও প্রকৃত প্রভাব নেই, তবে যদি আপনি আপনার কোডটি এমন বোর্ডে পোর্ট করেন তবে একটি বড় সঞ্চয়।
মাজেঙ্কো

5

মাকেনকো-র উত্তরের উত্তরে বিস্তারিত জানাতে, সংকলক আপনাকে এ সম্পর্কে সতর্ক করার পিছনে একটি ভাল কারণ রয়েছে। আসুন একটি পরীক্ষা স্কেচ করা যাক:

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"আপনার কোডে একাধিকবার স্ট্রিংটি উল্লেখ করেন তবে তাদের সকলকে একই মেমরি বরাদ্দ করার অনুমতি দেওয়া হবে। এখন আপনি যদি কোনওটিকে সংশোধন করেন তবে আপনি সেগুলি সমস্ত সংশোধন করুন!


পবিত্র ধোঁয়া! কে জানত ... সর্বশেষতম আরডুইনোইড সংকলকগুলির জন্য এটি এখনও সত্য? আমি এটি কেবল একটি ESP32 এ চেষ্টা করেছি এবং এটি বার বার গুরুমেডেটিশন ত্রুটির কারণ হয়ে থাকে ।
not2qubit

@ not2qubit আমি কেবল আরডিনো ১.৮.৯ এ পরীক্ষা করেছি এবং এটি সেখানে সত্য।
নিক গ্যামন

সতর্কতা একটি কারণ আছে। এবার আমি পেয়েছি: সতর্কতা: আইএসও সি ++ স্ট্রিং ধ্রুবককে 'চর ' এ রূপান্তর করতে নিষেধ করেছে [-Wwrit-तारগুলি] চর বার = "এটি কিছু পাঠ্য"; - ফোবিডস একটি শক্ত শব্দ। যেহেতু আপনাকে এটি করতে নিষেধ করা হয়েছে, তাই সংকলক চারপাশে ছিদ্র এবং দুটি স্ট্রিমের সাথে একই স্ট্রিং ভাগ করে নিতে বিনামূল্যে। নিষিদ্ধ কাজ করবেন না ! (এছাড়াও, সতর্কতাগুলি পড়ুন এবং বাদ দিন)। :)
নিক গ্যামন

সুতরাং আপনি যদি এই জাতীয় ক্রেপি কোডটি দেখতে পান এবং দিনটি টিকিয়ে রাখতে চান। একটি প্রাথমিক ঘোষণা করবে *fooএবং *barব্যবহার বিভিন্ন স্ট্রিং "ধ্রুবক" , কিন্তু তা ঠেকানোর? এছাড়াও, কোনও স্ট্রিং একেবারে না লাগানো থেকে এটি কীভাবে আলাদা: যেমন char *foo;?
not2qubit

1
বিভিন্ন ধ্রুবক সাহায্য করতে পারে, তবে ব্যক্তিগতভাবে আমি সেখানে কিছুই রাখতাম না এবং পরে সেখানে স্বাভাবিক উপায়ে ডেটা রাখি (উদাহরণস্বরূপ new, strcpyএবং delete)।
নিক দম্ভোক্তি

4

হয় স্ট্রিং ধ্রুবকটি অতিক্রম করার চেষ্টা বন্ধ করুন যেখানে কোনও ফাংশনটি লাগে char*, বা ফাংশনটি পরিবর্তন করে যাতে এটি const char*পরিবর্তে নেয় ।

"এলোমেলো স্ট্রিং" এর মতো স্ট্রিংগুলি ধ্রুবক।


"এলোমেলো অক্ষর" এর মতো একটি পাঠ্য কি ধ্রুব চর?
ফেডেরিকো কোরাজা

1
স্ট্রিং লিটারালগুলি স্ট্রিং কনস্ট্যান্ট।
ইগনাসিও ওয়াজকেজ-আব্রামস

3

উদাহরণ:

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একটি চর * (যা এটি তাই সংশোধন করতে পারে) প্রত্যাশা করে তবে আপনি একটি স্ট্রিং আক্ষরিক দিয়ে যাচ্ছেন, যা পরিবর্তন করা উচিত নয়।

সংকলক আপনাকে এটি না করার জন্য সতর্ক করে দিচ্ছে। অবহেলিত হওয়ার কারণে এটি একটি সতর্কতা থেকে ভবিষ্যতের সংকলক সংস্করণে একটি ত্রুটিতে পরিণত হতে পারে।


সমাধান: foo একটি প্রতিস্থাপন চর নিতে * করুন:

void foo (const char * s)
  {
  Serial.println (s);
  }

আমি পাই না। আপনার মানে কি সংশোধন করা যায় না ?

সি (এবং সি ++) এর পুরানো সংস্করণগুলি আপনাকে উপরের আমার উদাহরণের মতো কোড লিখতে দেয়। আপনি এমন একটি ফাংশন তৈরি করতে পারেন (যেমন foo) যা আপনি এতে প্রেরণ করেন এমন কিছু প্রিন্ট করে এবং তারপরে একটি আক্ষরিক স্ট্রিং (যেমন foo ("Hi there!");))

তবে একটি ফাংশন যা char *আর্গুমেন্ট হিসাবে গ্রহণ করে তার যুক্তিটি সংশোধন করার অনুমতি দেওয়া হয় (অর্থাত্ Hi there!এই ক্ষেত্রে সংশোধন করা)।

আপনি লিখে থাকতে পারেন, উদাহরণস্বরূপ:

void foo (char * s)
  {
  Serial.println (s);
  strcpy (s, "Goodbye");
  }

দুর্ভাগ্যক্রমে, একটি আক্ষরিক অর্থে পাস করার মাধ্যমে, আপনি এখন সম্ভাব্যভাবে সেই আক্ষরিক সংশোধন করেছেন যাতে "হাই হাই!" এখন "বিদায়" যা ভাল নয়। আসলে আপনি যদি আরও দীর্ঘ স্ট্রিংয়ে অনুলিপি করেন তবে আপনি অন্যান্য ভেরিয়েবলগুলি ওভাররাইট করতে পারেন। অথবা, কিছু বাস্তবায়নে আপনি অ্যাক্সেস লঙ্ঘন পাবেন কারণ "হাই হাই!" কেবল পঠনযোগ্য (সুরক্ষিত) র্যামে রাখা হয়েছে।

সুতরাং সংকলক-লেখকরা ধীরে ধীরে এই ব্যবহারকে অবনতি করছেন , যাতে আপনি যে আক্ষরিক অর্থে আক্ষরিক অর্থে চলেছেন, সেই যুক্তিটি অবশ্যই হিসাবে ঘোষণা করতে হবে const


আমি যদি পয়েন্টার না ব্যবহার করি তবে কী সমস্যা হয়?
ফেডেরিকো কোরাজা

কী ধরণের সমস্যা? এই নির্দিষ্ট সতর্কতাটি একটি স্ট্রিং ধ্রুবককে একটি চর * পয়েন্টারে রূপান্তরিত করার বিষয়ে। তুমি কি বিস্তারিত বলতে পারো?
নিক গ্যামন

@ নিক: আপনি কী বোঝাতে চেয়েছেন "(..) আপনি একটি স্ট্রিং আক্ষরিক পাস করছেন, যা পরিবর্তন করা উচিত নয়"। আমি পাই না। আপনি কি can notসংশোধন করা মানে ?
ম্যাডস স্কজার্ন

আমি আমার উত্তরটি পরিবর্তন করেছি। মাজেঙ্কো তার উত্তরে এই পয়েন্টগুলির বেশিরভাগ অংশ জুড়েছিলেন।
নিক গ্যামন

1

আমার এই সংকলন ত্রুটি রয়েছে:

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

এবং সংকলন ভাল হয়।


3
এই পরিবর্তনটি অক্ষরের মূলধন টিয়ের জন্য ASCII কোডের মান সহ একটি অক্ষরের স্ট্রিং "T" থেকে একটি একক অক্ষরে সংজ্ঞায়িত করে
16
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.