এই ত্রুটির অর্থ কী? আমি এটি কোনওভাবেই সমাধান করতে পারি না।
সতর্কতা: স্ট্রিং ধ্রুবক থেকে 'চর *' এ রূপান্তরকরণ [-Wwrit-तार]]
এই ত্রুটির অর্থ কী? আমি এটি কোনওভাবেই সমাধান করতে পারি না।
সতর্কতা: স্ট্রিং ধ্রুবক থেকে 'চর *' এ রূপান্তরকরণ [-Wwrit-तार]]
উত্তর:
আমার অভ্যাস হিসাবে, আমি এই ত্রুটিটির কারণগুলি এবং এর কারণগুলির মধ্যে কিছুটা পটভূমি প্রযুক্তিগত তথ্য সরবরাহ করতে যাচ্ছি।
আমি সি স্ট্রিংগুলি সূচনা করার চারটি ভিন্ন উপায়ে পরিদর্শন করতে যাচ্ছি এবং তাদের মধ্যে পার্থক্য কী তা দেখুন। এই চারটি প্রশ্নে উপায়:
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";
PROGMEM
, PSTR()
অথবা F()
। সুতরাং, এর const char text[]
চেয়ে বেশি র্যাম ব্যবহার করে না const char *text
।
(const char *)(...)
ing ালাই হিসাবে সংজ্ঞায়িত করে to বোর্ডের প্রয়োজন না থাকলে কোনও প্রকৃত প্রভাব নেই, তবে যদি আপনি আপনার কোডটি এমন বোর্ডে পোর্ট করেন তবে একটি বড় সঞ্চয়।
মাকেনকো-র উত্তরের উত্তরে বিস্তারিত জানাতে, সংকলক আপনাকে এ সম্পর্কে সতর্ক করার পিছনে একটি ভাল কারণ রয়েছে। আসুন একটি পরীক্ষা স্কেচ করা যাক:
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
একটি চর * (যা এটি তাই সংশোধন করতে পারে) প্রত্যাশা করে তবে আপনি একটি স্ট্রিং আক্ষরিক দিয়ে যাচ্ছেন, যা পরিবর্তন করা উচিত নয়।
সংকলক আপনাকে এটি না করার জন্য সতর্ক করে দিচ্ছে। অবহেলিত হওয়ার কারণে এটি একটি সতর্কতা থেকে ভবিষ্যতের সংকলক সংস্করণে একটি ত্রুটিতে পরিণত হতে পারে।
সমাধান: 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
সংশোধন করা মানে ?
আমার এই সংকলন ত্রুটি রয়েছে:
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
এবং সংকলন ভাল হয়।