স্ট্রিং আক্ষরিক: তারা কোথায় যায়?


161

আমি আগ্রহী যেখানে স্ট্রিং লিটারালগুলি বরাদ্দ / সঞ্চিত হয়।

আমি এখানে একটি আকর্ষণীয় উত্তর পেয়েছি :

একটি স্ট্রিং ইনলাইন সংজ্ঞায়িত করা প্রোগ্রামে নিজেই ডেটা এম্বেড করে এবং পরিবর্তন করা যায় না (কিছু সংকলক স্মার্ট ট্রিক দ্বারা এটি অনুমতি দেয়, বিরক্ত করবেন না)।

তবে, এটি সি ++ এর সাথে করার ছিল, এটি বিরক্ত করবেন না বলে উল্লেখ করা উচিত নয়।

আমি বিরক্ত করছি। = D:

সুতরাং আমার প্রশ্নটি কোথায় এবং কিভাবে আমার স্ট্রিং আক্ষরিক রাখা হয়? আমি কেন এটি পরিবর্তন করার চেষ্টা করব না? প্ল্যাটফর্মের মাধ্যমে বাস্তবায়ন কি আলাদা হয়? কেউ কি "স্মার্ট ট্রিক" এর বিস্তারিত বর্ণনা করতে আগ্রহী?

উত্তর:


125

একটি সাধারণ কৌশল হ'ল স্ট্রিং লিটারালগুলিকে "কেবলমাত্র পঠনযোগ্য ডেটা" বিভাগে রাখা হয় যা প্রক্রিয়া স্পেসে কেবল পঠনযোগ্য হিসাবে ম্যাপ করা হয় (এজন্য আপনি এটি পরিবর্তন করতে পারবেন না)।

এটি প্ল্যাটফর্ম অনুসারে পৃথক হয়। উদাহরণস্বরূপ, সহজ চিপ আর্কিটেকচারগুলি কেবল পঠনযোগ্য মেমরি বিভাগগুলিকে সমর্থন করে না তাই ডেটা বিভাগটি লিখনযোগ্য হবে।

তারপরে স্ট্রিং লিটারেলগুলিকে পরিবর্তনযোগ্য করে তোলার একটি কৌশল বের করার চেষ্টা করুন (এটি আপনার প্ল্যাটফর্মের উপর নির্ভরশীল এবং সময়ের সাথে সাথে পরিবর্তিত হতে পারে), কেবল অ্যারে ব্যবহার করুন:

char foo[] = "...";

সংকলক অ্যারেটি আক্ষরিক থেকে আরম্ভ করার ব্যবস্থা করবে এবং আপনি অ্যারেটি সংশোধন করতে পারবেন।


5
হ্যাঁ, আমি যখন পরিবর্তনীয় স্ট্রিং রাখতে চাই তখন আমি অ্যারেগুলি ব্যবহার করি। আমি শুধু কৌতুহলী ছিলাম. ধন্যবাদ।
ক্রিস কুপার

2
পরিবর্তনীয় স্ট্রিংয়ের জন্য অ্যারে ব্যবহার করার সময় আপনাকে বাফার ওভারফ্লো সম্পর্কে সতর্কতা অবলম্বন করতে হবে, যদিও - কেবল অ্যারের দৈর্ঘ্যের চেয়ে দীর্ঘতর স্ট্রিং লিখলে (যেমন foo = "hello"এই ক্ষেত্রে) অনিচ্ছাকৃত পার্শ্ব-প্রতিক্রিয়া ঘটাতে পারে ... (ধরে নিলে আপনি পুনরায় না - সঙ্গে মেমরি বণ্টন newবা কিছু)
জনি

2
অ্যারে স্ট্রিং ব্যবহার করার সময় কি স্ট্যাক বা অন্য কোথাও যায়?
সুরজ জৈন

char *p = "abc";@ ক্রিসকোপার
কেপিএমজি ২

52

এর কোনও উত্তর নেই। সি এবং সি ++ স্ট্যান্ডার্ড কেবল বলেছে যে স্ট্রিং লিটারেলের স্থিতিশীল স্টোরেজ সময়কাল থাকে, এগুলিকে সংশোধন করার যে কোনও প্রচেষ্টা অনির্ধারিত আচরণ দেয় এবং একই বিষয়বস্তু সহ একাধিক স্ট্রিং লিটারাল একই স্টোরেজ ভাগ করতে পারে বা নাও করতে পারে।

আপনি যে সিস্টেমটি লিখছেন তার উপর নির্ভর করে এবং এটি ব্যবহার করে এমন এক্সিকিউটেবল ফাইল ফর্ম্যাটের ক্ষমতাগুলির উপর নির্ভর করে সেগুলি পাঠ্য বিভাগে প্রোগ্রাম কোডের সাথে সংরক্ষণ করা যেতে পারে বা তাদের আরম্ভিক ডেটার জন্য পৃথক বিভাগ থাকতে পারে।

প্ল্যাটফর্মের উপর নির্ভর করে বিশদগুলি নির্ধারণ করাও পৃথক হতে পারে - সম্ভবত সম্ভবত এমন সরঞ্জামগুলি অন্তর্ভুক্ত রয়েছে যা আপনাকে এটি কোথায় লাগিয়েছে তা বলতে পারে। এমনকি কিছু চাইলে আপনি এ জাতীয় বিশদ নিয়ন্ত্রণ করতে পারবেন (উদাহরণস্বরূপ gnu ld আপনাকে স্ক্রিপ্ট সরবরাহ করার অনুমতি দেয় কীভাবে এটি কীভাবে গ্রুপের ডেটা, কোড ইত্যাদি করা যায় সে সম্পর্কে সব কিছু জানাতে)


1
আমি এটি অসম্ভব বলে মনে করি যে স্ট্রিং ডেটা সরাসরি টেক্সট সেগমেন্টে সংরক্ষণ করা হবে। সত্যিই সংক্ষিপ্ত আক্ষরিক জন্য, আমি সংকলক উত্পন্ন কোড দেখতে পেলাম যেমন movb $65, 8(%esp); movb $66, 9(%esp); movb $0, 10(%esp)স্ট্রিংয়ের জন্য "AB", তবে সময়ের সিংহভাগ এটি একটি নন-কোড সেগমেন্টে যেমন .dataবা .rodataবা এর মতো হবে (লক্ষ্যটি সমর্থন করে বা না তার উপর নির্ভর করে) কেবল পঠন বিভাগগুলি)।
অ্যাডাম রোজেনফিল্ড

স্ট্রিং লিটারাল যদি প্রোগ্রামের পুরো সময়কালের জন্য বৈধ হয়, এমনকি স্ট্যাটিক অবজেক্টগুলির ধ্বংসের সময়ও তবে স্ট্রিং আক্ষরিকের সাথে কনস্ট্রাক্ট রেফারেন্সটি ফেরানো বৈধ? কেন এই প্রোগ্রামটি রানটাইম ত্রুটি দেখায় আদর্শ দেখুন / এফটিএস 1 আইজি
ধ্বংসকারী

@ অ্যাডামরোসেনফিল্ড: আপনি যদি কিছুটা বিরক্ত হন তবে আপনি ইউনিক্স a.out ফর্ম্যাটটি (যেমন, freebsd.org/cgi/… ) লিগ্যাসিটি দেখতে পারেন (উদাহরণস্বরূপ )। আপনার যে বিষয়টি দ্রুত লক্ষ্য করা উচিত তা হ'ল এটি কেবল একটি ডেটা বিভাগকে সমর্থন করে যা সর্বদা লিখিত হয়। সুতরাং আপনি যদি কেবল পঠনযোগ্য স্ট্রিং আক্ষরিক চান তবে মূলত তারা যেতে পারেন কেবলমাত্র পাঠ্য বিভাগ (এবং হ্যাঁ, সেই সময়ে লিঙ্কারগুলি প্রায়শই ঠিক তাই করেছিল)।
জেরি কফিন

48

আমি কেন এটি পরিবর্তন করার চেষ্টা করব না?

কারণ এটি অনির্ধারিত আচরণ। C99 N1256 খসড়া 6.7.8 / 32 "সূচনা" থেকে উদ্ধৃতি :

উদাহরণ 8: ঘোষণা

char s[] = "abc", t[3] = "abc";

"প্লেইন" চর অ্যারে অবজেক্টগুলি সংজ্ঞায়িত করে sএবং tযার উপাদানগুলি অক্ষর স্ট্রিং ল্যাটারাল দিয়ে শুরু করা হয়।

এই ঘোষণাটি সমান

char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

অ্যারের সামগ্রীগুলি পরিবর্তনযোগ্য if অন্যদিকে, ঘোষণা

char *p = "abc";

p"পয়েন্টার টু চর" টাইপ দিয়ে সংজ্ঞায়িত করে এবং এটি দৈর্ঘ্য 4 দিয়ে "চরের অ্যারে" টাইপযুক্ত কোনও বস্তুর দিকে নির্দেশ করতে ইনিশিয়ালাইজ করে যার উপাদানগুলি একটি অক্ষর স্ট্রিং আক্ষরিক দিয়ে প্রাথমিক হয়। pঅ্যারের বিষয়বস্তুগুলি সংশোধন করার জন্য যদি চেষ্টা করা হয় , তবে আচরণটি সংজ্ঞায়িত।

যেখানে তারা যেতে না?

জিসিসি 4.8 x86-64 ইএলএফ উবুন্টু 14.04:

  • char s[]: স্ট্যাক
  • char *s:
    • .rodata অবজেক্ট ফাইলের বিভাগ
    • একই বিভাগ যেখানে .textঅবজেক্ট ফাইলের বিভাগটি ডাম্প হয়ে যায়, এতে রড এবং এক্সিকিউট অনুমতি রয়েছে তবে লিখুন না

কার্যক্রম:

#include <stdio.h>

int main() {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}

সংকলন এবং পচনশীল:

gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o

আউটপুট রয়েছে:

 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata

সুতরাং স্ট্রিংটি .rodataবিভাগে সঞ্চিত আছে ।

তারপর:

readelf -l a.out

রয়েছে (সরলীকৃত):

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000704 0x0000000000000704  R E    200000

 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata

এর অর্থ এই যে ডিফল্ট linker স্ক্রিপ্ট উভয় ডাম্প .textএবং .rodataএকটি সেগমেন্ট যে মৃত্যুদন্ড কার্যকর করা যেতে পারে কিন্তু পরিবর্তন করা মধ্যে ( Flags = R E)। এই জাতীয় বিভাগটি সংশোধন করার চেষ্টা করা লিনাক্সে সেগফল্টের দিকে নিয়ে যায়।

আমরা যদি এর জন্য একই করি char[]:

 char s[] = "abc";

আমরা প্রাপ্ত:

17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)

সুতরাং এটি স্ট্যাকের মধ্যে (তুলনামূলক %rbp) সঞ্চিত হয়ে যায় এবং আমরা অবশ্যই এটি সংশোধন করতে পারি।


22

এফওয়াইআই, কেবলমাত্র অন্য উত্তরগুলির ব্যাক আপ করছে:

মান: আইএসও / আইইসি 14882: 2003 বলেছেন:

2.13। স্ট্রিং আক্ষরিক

  1. [...] একটি সাধারণ স্ট্রিং আক্ষরিকের টাইপ থাকে "অ্যারে অফ n const char" এবং স্ট্যাটিক স্টোরেজ সময়কাল (3.7)

  2. সমস্ত স্ট্রিং আক্ষরিক স্বতন্ত্র কিনা (তা হ'ল ননওরোলাপিং অবজেক্টগুলিতে সঞ্চিত) বাস্তবায়ন-সংজ্ঞায়িত। একটি স্ট্রিং আক্ষরিক সংশোধন করার চেষ্টা করার প্রভাবটি সংজ্ঞায়িত।


2
সহায়ক তথ্য, তবে নোটিশ লিংকটি সি ++ এর জন্য, যেখানে প্রশ্নটি সি
বাঁধা

1
2.13 এ # 2 টি নিশ্চিত হয়েছে। ওস বিকল্প (আকারের জন্য অনুকূলিতকরণ) সহ, জিসিসি .rodata এ স্ট্রিং লিটারেলগুলিকে ওভারল্যাপ করে।
পেং ঝাং

14

জিসিসি একটি .rodataবিভাগ তৈরি করে যা ঠিকানা জায়গায় "কোথাও" ম্যাপ করা হয়ে থাকে এবং কেবলমাত্র পঠিত হিসাবে চিহ্নিত হয়,

ভিজ্যুয়াল সি ++ ( cl.exe) .rdataএকই উদ্দেশ্যে একটি বিভাগ তৈরি করে।

আপনি এর থেকে আউটপুট তাকান পারেন dumpbinবা objdump(লিনাক্সের দিকে) আপনার এক্সিকিউটেবল বিভাগে দেখতে।

যেমন

>dumpbin vec1.exe
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file vec1.exe

File Type: EXECUTABLE IMAGE

  Summary

        4000 .data
        5000 .rdata  <-- here are strings and other read-only stuff.
       14000 .text

1
অজডাম্প দিয়ে কীভাবে rdata বিভাগটি বিচ্ছিন্ন করা যায় তা আমি দেখতে পাচ্ছি না।
ব্যবহারকারী 2284570

@ ব্যবহারকারী 2284570, এটি কারণ যে বিভাগে বিধানসভা থাকে না। এটিতে ডেটা রয়েছে।
অ্যালেক্স বুদোভস্কি

1
আরও পঠনযোগ্য আউটপুট পেতে কেবল একটি বিষয়। আমি বোঝাতে চাই যে আমি of বিভাগগুলিতে ঠিকানার পরিবর্তে স্ট্রিংগুলি ডিসঅাসেপ্সেসের সাথে যুক্ত করতে চাই। (হেম আপনি সি এর printf("some null terminated static string");পরিবর্তে জানেন printf(*address);)
ব্যবহারকারী 2284570

4

এটি আপনার এক্সিকিউটেবলের ফর্ম্যাটের উপর নির্ভর করে । এটি সম্পর্কে চিন্তা করার একটি উপায় হ'ল আপনি যদি অ্যাসেমব্লিং প্রোগ্রামিং করতেন তবে আপনার সমাবেশ প্রোগ্রামের ডেটা বিভাগে স্ট্রিং লিটারেল যুক্ত হতে পারে। আপনার সি সংকলক এর মতো কিছু করে তবে এটি আপনি নির্ভর করে যে আপনি বাইনারি কোন সিস্টেমটি তৈরি করছেন তা তার উপর নির্ভর করে।


2

স্ট্রিং লিটারেলগুলি কেবলমাত্র পঠনযোগ্য মেমরির জন্য প্রায়শই বরাদ্দ করা হয়, এগুলি অদলযোগ্য। যাইহোক, কিছু সংকলকগুলিতে "স্মার্ট ট্রিক" দ্বারা পরিবর্তন সম্ভব হয় .. এবং স্মার্ট ট্রিকটি "স্মৃতিতে নির্দেশিত চরিত্র পয়েন্টার ব্যবহার করে" হয় .. কিছু সংকলক মনে রাখবেন, এটি অনুমোদন করতে পারে না এখানে এখানে ডেমো

char *tabHeader = "Sound";
*tabHeader = 'L';
printf("%s\n",tabHeader); // Displays "Lound"

0

এটি সংকলক থেকে সংকলক হিসাবে পৃথক হতে পারে, সর্বাধিক উপায় অনুসন্ধান স্ট্রিং আক্ষরিক জন্য একটি বস্তু ডাম্প ফিল্টার করা হয়:

objdump -s main.o | grep -B 1 str

যেখানে সমস্ত বিভাগের সম্পূর্ণ বিষয়বস্তু প্রদর্শন করার জন্য -sবাধ্য করা objdumpহয়, main.oএটি হ'ল অবজেক্ট ফাইল, ম্যাচের আগে একটি লাইনও প্রিন্ট করতে -B 1বাধ্য grepকরে (যাতে আপনি বিভাগটির নামটি দেখতে পারেন) এবং strএটি যে স্ট্রিংটি আপনি অনুসন্ধান করছেন তা হ'ল।

উইন্ডোজ মেশিনে জিসিসি সহ এবং একটি ভেরিয়েবলের mainমতো ঘোষিত

char *c = "whatever";

চলমান

objdump -s main.o | grep -B 1 whatever

আয়

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