সি স্ট্রিং লিটারেলগুলি কেবল পঠনযোগ্য?


29

স্ট্রিং লিটারালদের কেবল-পঠনযোগ্য (-ies / -ied) ন্যায্যতাযুক্ত কী সুবিধা (গুলি):

  1. নিজেকে পায়ে গুলি করার আর একটি উপায়

    char *foo = "bar";
    foo[0] = 'd'; /* SEGFAULT */
    
  2. এক লাইনে শব্দের একটি পঠন-রাইনের বিন্যাসটি মার্জিতভাবে শুরু করতে অক্ষম:

    char *foo[] = { "bar", "baz", "running out of traditional placeholder names" };
    foo[1][2] = 'n'; /* SEGFAULT */ 
    
  3. ভাষা নিজেই জটিল।

    char *foo = "bar";
    char var[] = "baz";
    some_func(foo); /* VERY DANGEROUS! */
    some_func(var); /* LESS DANGEROUS! */
    

স্মৃতি সংরক্ষণ করছেন? আমি কোথাও পড়েছি (এখনই উত্সটি খুঁজে পাইনি), যখন র‌্যামের দুষ্প্রাপ্যতা ছিল, সংকলকরা অনুরূপ স্ট্রিংগুলিকে মার্জ করে মেমরির ব্যবহারটি সর্বোত্তম করার চেষ্টা করেছিল।

উদাহরণস্বরূপ, "আরও" এবং "রেজেক্স" "মোরেজেক্স" হয়ে যাবে। ডিজিটাল ব্লু-রে মানের চলচ্চিত্রের যুগে আজও কি এটি সত্য? আমি বুঝতে পারি যে এম্বেড থাকা সিস্টেমগুলি এখনও সীমাবদ্ধ সংস্থাগুলির পরিবেশে কাজ করে তবে এখনও উপলব্ধ মেমরির পরিমাণ নাটকীয়ভাবে বেড়েছে।

উপযুক্ততা বিষয়? আমি ধরে নিয়েছি যে কেবলমাত্র পঠনযোগ্য মেমরির অ্যাক্সেস করার চেষ্টা করবে এমন একটি উত্তরাধিকারসূচক প্রোগ্রামটি ক্র্যাশ হয়ে যাবে বা অদোষিত বাগ সহ চালিয়ে যাবে। সুতরাং কোনও লিগ্যাসি প্রোগ্রাম স্ট্রিং আক্ষরিক অ্যাক্সেস করার চেষ্টা করা উচিত নয় এবং এর জন্য স্ট্রিং আক্ষরিককে লেখার অনুমতি দিয়ে বৈধ, নন-হ্যাকিশ, পোর্টেবল উত্তরাধিকার প্রোগ্রামগুলির ক্ষতি করতে পারে না ।

অন্য কোন কারণ আছে? আমার যুক্তি কি ভুল? নতুন সি স্ট্যান্ডার্ডে স্ট্রিং লিটারে রিড-লিখনের পরিবর্তনের বিষয়টি বিবেচনা করা বা কমপক্ষে সংকলনের বিকল্প যুক্ত করা যুক্তিসঙ্গত হবে কি? এটি কি আগে বিবেচিত হয়েছিল বা আমার "সমস্যাগুলি" খুব সংক্ষিপ্ত এবং কাউকে বিরক্ত করার জন্য তুচ্ছ?


12
আমি ধরে নিয়েছি আপনি সংকলিত কোডটিতে স্ট্রিং লিটারালগুলি কীভাবে দেখছেন তা দেখেছেন ?

2
আমি যে লিঙ্কটি দিয়েছি তা সমাবেশটি দেখুন। ঠিক আছে।

8
নাল সমাপ্তির কারণে আপনার "মোরগেক্স" উদাহরণটি কাজ করবে না।
dan04

4
আপনি ধ্রুবকগুলির উপরে লিখতে চান না কারণ এটি তাদের মান পরিবর্তন করবে। পরের বার আপনি একই ধ্রুবকটি ব্যবহার করতে চাইলে এটি আলাদা হবে। সংকলক / রানটাইমটি কোথাও থেকে ধ্রুবকগুলি উত্স করতে হবে এবং যেখানেই সেগুলি আপনাকে সংশোধন করার অনুমতি দেওয়া উচিত নয়।
এরিক tদ

1
'সুতরাং স্ট্রিং লিটারালগুলি প্রোগ্রাম মেমোরিতে সংরক্ষণ করা হয়, র‌্যাম নয়, এবং বাফার ওভারফ্লো এর ফলে প্রোগ্রামটি নিজেই দুর্নীতিতে ডেকে আনে?' প্রোগ্রামের চিত্রটিও র‍্যামে রয়েছে। সুনির্দিষ্টভাবে বলতে গেলে স্ট্রিং লিটারালগুলি একই চিত্রের র‌্যামে র‌্যামের জন্য সংরক্ষণ করা হয় যা প্রোগ্রামের চিত্রটি সঞ্চয় করতে ব্যবহৃত হয়। এবং হ্যাঁ, স্ট্রিং ওভাররাইট করা প্রোগ্রামটিকে দূষিত করতে পারে। এমএস-ডস এবং সিপি / এম এর দিনগুলিতে কোনও মেমরি সুরক্ষা ছিল না, আপনি এ জাতীয় জিনিসগুলি করতে পারেন এবং এটি সাধারণত ভয়াবহ সমস্যার সৃষ্টি করে। প্রথম পিসি ভাইরাসগুলি আপনার প্রোগ্রামটি পরিবর্তন করতে এমন কৌশল ব্যবহার করবে যাতে আপনি এটি চালানোর চেষ্টা করার সময় এটি আপনার হার্ড ড্রাইভকে ফর্ম্যাট করে।
চার্লস ই। গ্রান্ট

উত্তর:


40

Icallyতিহাসিকভাবে (সম্ভবত এর অংশগুলি পুনরায় লিখে) এটি বিপরীত ছিল। ১৯ 1970০- এর দশকের গোড়ার দিকে প্রথম কম্পিউটারে (সম্ভবত পিডিপি -11 ) প্রোটোটাইপিকাল এম্ব্রোনিক সি চালানো হয়েছিল (সম্ভবত বিসিপিএল ) কোনও এমএমইউ ছিল না এবং কোনও মেমরি সুরক্ষা ছিল না (যা বেশিরভাগ পুরানো আইবিএম / 360 মেইনফ্রেমে বিদ্যমান ছিল )। সুতরাং মেমোরির প্রতিটি বাইট (যারা আক্ষরিক স্ট্রিং বা মেশিন কোড পরিচালনা করে) সহ একটি ভুল প্রোগ্রাম দ্বারা ওভাররাইট করা যেতে পারে (কল্পনা করুন যে কোনও প্রোগ্রামকে প্রিন্টফ (3) ফর্ম্যাট স্ট্রিংয়ে কিছুতে পরিবর্তন %করা /হয়েছে )। সুতরাং, আক্ষরিক স্ট্রিং এবং ধ্রুবকগুলি লিখনযোগ্য ছিল।

1975 সালে কিশোর বয়সে, আমি 1960 এর দশকের পুরানো কম্পিউটারগুলিতে মেমরির সুরক্ষা ছাড়াই প্যারিসের প্যালিস দে লা ডকুভার্ট যাদুঘরে কোড করেছিলাম: আইবিএম / 1620 এর একটি মূল মেমরি ছিল - যা আপনি কীবোর্ডের মাধ্যমে সূচনা করতে পেরেছিলেন, তাই আপনাকে কয়েক ডজন টাইপ করতে হয়েছিল খোঁচা টেপে প্রাথমিক প্রোগ্রামটি পড়তে অঙ্কগুলি; সিএবি / 500 এর চৌম্বকীয় ড্রামের স্মৃতি ছিল; আপনি ড্রাম কাছাকাছি যান্ত্রিক সুইচ মাধ্যমে কিছু ট্র্যাক লিখতে অক্ষম করতে পারে।

পরে, কম্পিউটারগুলি কিছু স্মৃতি সুরক্ষা সহ মেমরি ম্যানেজমেন্ট ইউনিটের (এমএমইউ) কিছু ফর্ম পেয়েছিল। এমন একটি ডিভাইস ছিল যা সিপিইউকে কিছু ধরণের মেমরির ওভাররাইট করতে নিষেধ করে। সুতরাং কিছু মেমরি বিভাগ, উল্লেখযোগ্যভাবে কোড সেগমেন্ট (ওরফে .textবিভাগ) কেবল পঠনযোগ্য হয়ে উঠেছে (অপারেটিং সিস্টেম বাদে যা সেগুলি ডিস্ক থেকে লোড করে)। সংকলক এবং লিঙ্কারের পক্ষে সেই কোড বিভাগে আক্ষরিক স্ট্রিংগুলি রাখা স্বাভাবিক ছিল এবং আক্ষরিক স্ট্রিংগুলি কেবল পঠনযোগ্য হয়ে ওঠে। যখন আপনার প্রোগ্রাম সেগুলি ওভাররাইট করার চেষ্টা করেছিল, তখন এটি খারাপ ছিল, একটি সংজ্ঞায়িত আচরণ । এবং ভার্চুয়াল মেমরিতে কেবল পঠনযোগ্য কোড বিভাগ থাকা একটি উল্লেখযোগ্য সুবিধা দেয়: একই প্রোগ্রামে চলমান বেশ কয়েকটি প্রক্রিয়া একই র‌্যাম ভাগ করে ( শারীরিক স্মৃতি)পৃষ্ঠাগুলি) সেই কোড বিভাগের MAP_SHAREDজন্য ( লিনাক্সে এমএম্যাপের জন্য পতাকা দেখুন (2) )।

আজ, সস্তা মাইক্রোকন্ট্রোলারদের কিছু পঠনযোগ্য মেমরি রয়েছে (যেমন তাদের ফ্ল্যাশ বা রম) এবং তাদের কোডটি (এবং আক্ষরিক স্ট্রিং এবং অন্যান্য ধ্রুবকগুলি) সেখানে রাখে। এবং প্রকৃত মাইক্রোপ্রসেসরগুলি (আপনার ট্যাবলেট, ল্যাপটপ বা ডেস্কটপের মতো) একটি অত্যাধুনিক মেমরি পরিচালনা ইউনিট এবং ভার্চুয়াল মেমরি এবং পেজিংয়ের জন্য ক্যাশে যন্ত্রপাতি ব্যবহৃত হয় । সুতরাং এক্সিকিউটেবল প্রোগ্রামের কোড বিভাগটি (যেমন ELF ) মেমরিকে কেবল পঠনযোগ্য, ভাগযোগ্য এবং এক্সিকিউটেবল সেগমেন্ট হিসাবে ম্যাপ করা হয় (এমএমএপ (2 দ্বারা ) অথবা লিনাক্সে এক্সিকিউট (2) ; বিটিডাব্লু আপনি এলডি-কে নির্দেশ দিতে পারেনলিখিতযোগ্য কোড বিভাগটি পেতে যদি আপনি সত্যিই চান)। এটি লিখতে বা অপব্যবহার করা সাধারণত একটি সেগমেন্টেশন দোষ

সুতরাং সি স্ট্যান্ডার্ডটি ব্যারোক: বৈধভাবে (কেবল historicalতিহাসিক কারণে), আক্ষরিক স্ট্রিংগুলি const char[]অ্যারে নয় , তবে কেবল char[]অ্যারেগুলি ওভাররাইট করা নিষিদ্ধ।

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

বর্তমান সি কম্পাইলার অপটিমাইজ এবং করতে পারবেন "ions"এবং "expressions"তাদের শেষ 5 (সসীম নাল বাইট সহ) বাইট শেয়ার করুন।

আপনার সি সি কোডটি ফাইলের foo.cসাথে সংকলন করার চেষ্টা করুন gcc -O -fverbose-asm -S foo.cএবং জিসিসিfoo.s দ্বারা উত্পন্ন এসেমব্লার ফাইলটি ভিতরে দেখুন

শেষ অবধি , সি এর শব্দার্থবিজ্ঞান যথেষ্ট জটিল ( কমপ্যাকার্ট এবং ফ্রেমা -সি সম্পর্কে এটি আরও পড়ুন যা এটি ক্যাপচার করার চেষ্টা করছে) এবং লিখনযোগ্য ধ্রুবক আক্ষরিক স্ট্রিংগুলি প্রোগ্রামকে দুর্বল এবং আরও কম সুরক্ষিত করার সময় এটি আরও তীব্রতর করে তুলবে (এবং কম সহ) সংজ্ঞায়িত আচরণ), সুতরাং এটি ভবিষ্যতের সি স্ট্যান্ডার্ডগুলি লিখনযোগ্য আক্ষরিক স্ট্রিং গ্রহণ করবে এমনটি খুব কমই। সম্ভবত বিপরীতে const char[]তারা নৈতিকভাবে হওয়া উচিত তাদের অ্যারে করে দেবে।

আরও লক্ষ করুন যে অনেক কারণে, পরিবর্তনীয় ডেটা স্থির তথ্যের চেয়ে কম্পিউটারের (ক্যাশে সুসংহত), কোড করার জন্য, বিকাশকারী দ্বারা বুঝতে সক্ষম হ্যান্ডেল করা আরও শক্ত। সুতরাং আপনার বেশিরভাগ ডেটা (এবং উল্লেখযোগ্য আক্ষরিক স্ট্রিংগুলি) অপরিবর্তনীয় থাকা ভাল । ফাংশনাল প্রোগ্রামিং দৃষ্টান্ত সম্পর্কে আরও পড়ুন ।

আইবিএম / 7094-এর পুরানো ফোর্টরান 7777 দিনগুলিতে একটি বাগ এমনকি একটি ধ্রুবক পরিবর্তন করতে পারে: আপনি CALL FOO(1)এবং যদি FOOএটির ২ টি রেফারেন্স অনুসারে তার যুক্তিটি সংশোধন করতে পারেন তবে বাস্তবায়নটি অন্যান্য সংঘটনগুলি 1 থেকে 2 এ পরিবর্তিত হতে পারে এবং এটি সত্যিই ছিল দুষ্টু বাগ, খুঁজে পাওয়া বেশ শক্ত।


এটি কি ধ্রুবক হিসাবে স্ট্রিং রক্ষা করতে? যদিও তারা constমান হিসাবে স্ট্যাকওভারফ্লো.com/ জিজ্ঞাসা / 2245664/… হিসাবে সংজ্ঞায়িত করা হয় না ?
মারিউস মাকিজাউসকাস

আপনি কি নিশ্চিত যে প্রথম কম্পিউটারগুলিতে কেবল পঠনযোগ্য মেমরি ছিল না ? এটি ভেড়ার চেয়ে যথেষ্ট সস্তা ছিল না? এছাড়াও, তাদের আরও-মেমোরিতে রাখার ফলে ইউবির ভুলভাবে তাদের সংশোধন করার চেষ্টা করার কারণ হয় না, তবে ওপিতে এটি করা হয় না এবং তিনি সেই বিশ্বাস লঙ্ঘন করে। উদাহরণস্বরূপ ফোর্টরান-প্রোগ্রামগুলি দেখুন যেখানে সমস্ত আক্ষরিক 1হঠাৎ 2
হ'ল

1
একটি যাদুঘরে কিশোর হিসাবে, আমি 1975 সালে পুরানো আইবিএম / 1620 এবং সিএবি 500 কম্পিউটারে কোড করেছিলাম। উভয়েরই কোনও রম ছিল না: আইবিএম / 1620 এর মূল মেমরি ছিল, এবং সিএবি 500 একটি চৌম্বকীয় ড্রাম ছিল (কিছু ট্র্যাকগুলি যান্ত্রিক সুইচ দ্বারা লিখিত হতে অক্ষম হতে পারে)
বেসিল স্টারিনকিভিচ

2
আরও উল্লেখ করার মতো: কোড সেগমেন্টে আক্ষরিক রাখার অর্থ সেগুলি প্রোগ্রামের একাধিক অনুলিপিগুলির মধ্যে ভাগ করা যায় কারণ সূচনাটি রান টাইমের পরিবর্তে সংকলন সময়ে ঘটে।
blrfl

@ ডিডুকিপেটর ওয়েল, আমি একটি বেসিক বৈকল্পিক চালিত একটি মেশিন দেখেছি যা আপনাকে পূর্ণসংখ্যার ধ্রুবক পরিবর্তন করতে দেয় (আমি নিশ্চিত নই যে এটির ক্ষেত্রে এটির কৌতুক করার দরকার ছিল কিনা, যেমন "বাইরেফ" আর্গুমেন্টগুলি পাস করা বা যদি কোনও সাধারণ let 2 = 3কাজ করে)। এটি অবশ্যই প্রচুর মজাদার (শব্দের বামন দুর্গের সংজ্ঞায়) ফলস্বরূপ। দোভাষীর কীভাবে এটির অনুমতি দেওয়া হয়েছিল তা কীভাবে তৈরি করা হয়েছিল তা আমার কোনও ধারণা নেই তবে এটি ছিল।
লুয়ান

2

কম্পাইলার একত্রিত পারে না "more"এবং "regex"পরে, কারণ সাবেক একটি নাল বাইট হয়েছে eযখন আধুনিক একটি হয়েছে x, কিন্তু অনেক কম্পাইলার স্ট্রিং লিটারেল যা পুরোপুরি মিলেছে একত্রিত হবে, এবং কিছু স্ট্রিং লিটারেল যে একটি সাধারণ লেজ ভাগ মেলে যাবে। কোড যা একটি স্ট্রিং আক্ষরিক পরিবর্তন করে সেভাবে বিভিন্ন স্ট্রিং আক্ষরিক পরিবর্তন হতে পারে যা কিছু সম্পূর্ণ ভিন্ন উদ্দেশ্যে ব্যবহৃত হয় তবে একই অক্ষরগুলি ধারণ করে।

সি আবিষ্কারের আগে ফরটারনে একই জাতীয় সমস্যা দেখা দেবে যুক্তিগুলি সর্বদা মানের পরিবর্তে ঠিকানার মাধ্যমেই পাস করা হত। দুটি সংখ্যা যুক্ত করার একটি রুটিন এইভাবে সমান হবে:

float sum(float *f1, float *f2) { return *f1 + *f2; }

ইভেন্টটিতে যে কোনও একটি স্থির মান (উদাহরণস্বরূপ 4.0) পাস করতে চেয়েছিল sum, সংকলকটি একটি বেনামে ভেরিয়েবল তৈরি করবে এবং এটিকে আরম্ভ করবে 4.0। যদি একই মান একাধিক ফাংশনে পাস করা হয় তবে সংকলক তাদের সকলের কাছে একই ঠিকানাটি পাস করবে। ফলস্বরূপ, যদি কোনও ফাংশন যা এর একটি প্যারামিটারকে সংশোধন করে একটি ভাসমান-বিন্দু ধ্রুবক পাস করা হয়, প্রোগ্রামের অন্য কোথাও সেই ধ্রুবকের মান পরিবর্তিত হতে পারে, ফলে এই প্রবাদটি "ভেরিয়েবলগুলি হবে না; ধ্রুবকগুলি স্থিতিশীল নয়" 'টি "।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.