কেন বরাদ্দ () ব্যবহার করা ভাল অভ্যাস হিসাবে বিবেচিত হয় না?


400

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

alloca()উপরোক্ত বৈশিষ্ট্য থাকা সত্ত্বেও কেন হতাশার ব্যবহার ?


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

9
এছাড়াও, বরাদ্দ ()) সহ কোনও ফাংশন যদি এরূপ হিসাবে ঘোষণা করা হয় তবে সেগুলিকে অন্তর্ভুক্ত করা হবে না।
জাস্টিকাল

2
@ জাস্টিকাল, আপনি কিছু ব্যাখ্যা দিতে পারেন? আমি এই আচরণের পিছনে কি খুব আগ্রহী
ম্যাগাজেক

47
বহনযোগ্যতা সম্পর্কে সমস্ত আওয়াজ ভুলে যান, কল করার দরকার নেই free(যা স্পষ্টতই একটি সুবিধা), এটির ইনলাইন করার অযোগ্যতা (স্পষ্টতই গাদা বরাদ্দ খুব বেশি ভারী) এবং ইত্যাদি এড়ানোর একমাত্র কারণ allocaহ'ল বড় আকারের for যে, স্ট্যাক মেমরি টন নষ্ট করা ভাল ধারণা নয়, এবং আপনার স্ট্যাকের ওভারফ্লো হওয়ার সম্ভাবনা রয়েছে। এই যদি হয় তাহলে - ব্যবহারের বিষয়ে বিবেচনা malloca/freea
valdo

5
এর আর একটি ইতিবাচক দিক allocaহ'ল স্ট্যাকটি গাদা মতো খণ্ডিত হতে পারে না। এটি হার্ড-রিয়েল-টাইম রান চিরকালের স্টাইল অ্যাপ্লিকেশনগুলির জন্য বা এমনকি সুরক্ষার সমালোচনামূলক অ্যাপ্লিকেশনগুলির পক্ষে কার্যকর প্রমাণিত হতে পারে, যেহেতু ডাব্লুসিআরইউ তখন নিজস্ব সমস্যার সাথে কাস্টম মেমরি পুলগুলিকে অবলম্বন না করে স্থিতিশীলভাবে বিশ্লেষণ করা যেতে পারে (কোনও সাময়িক লোকাল নয়, উপ-অনুকূল উত্স নয়) ব্যবহার)।
Andreas

উত্তর:


245

উত্তরটি ঠিক manপৃষ্ঠায় রয়েছে (কমপক্ষে লিনাক্সে ):

মান ফিরিয়ে দিন বরাদ্দ স্থানের শুরুতে বরাদ্দ () ফাংশনটি একটি পয়েন্টার দেয় ter যদি বরাদ্দের কারণে স্ট্যাকের ওভারফ্লো হয় তবে প্রোগ্রামের আচরণটি সংজ্ঞায়িত হয়।

এটি কখনই ব্যবহার করা উচিত নয় তা বলে। আমি যে ওএসএস প্রকল্পে কাজ করি তার মধ্যে একটি এটি ব্যাপকভাবে ব্যবহার করে এবং যতক্ষণ আপনি এটি অপব্যবহার না করে থাকেন ( alloca'বিশাল মূল্যবোধগুলি ইঙ্গিত করছেন ), ঠিক আছে। একবার আপনি "কয়েকশো বাইট" চিহ্নটি অতিক্রম করে গেলে malloc, পরিবর্তে পরিবর্তে এটি ব্যবহার করার সময় এবং বন্ধুদের। আপনি এখনও বরাদ্দ ব্যর্থতা পেতে পারেন, তবে কমপক্ষে আপনার কেবল স্ট্যাকটি ফুটিয়ে তোলার পরিবর্তে ব্যর্থতার কিছু ইঙ্গিত পাবেন।


35
সুতরাং এটির সাথে আসলেই কোনও সমস্যা নেই যা আপনার বড় অ্যারে ঘোষণা করার সাথেও না থাকে?
টেড

88
@ শীন: হ্যাঁ, স্ট্যাক ওভারফ্লো ঝুঁকি দেওয়া কারণ, তবে সেই কারণটি কিছুটা মূর্খ। প্রথমত কারণ (বৈভব যেমন বলেছেন) বৃহত্তর স্থানীয় অ্যারে ঠিক একই সমস্যা সৃষ্টি করে তবে প্রায় ততটুকু বিলীন হয় না। এছাড়াও, পুনরাবৃত্তি ঠিক সহজেই স্ট্যাকটি ফুঁকতে পারে। দুঃখিত তবে আমি আপনাকে আশা করছি যে এই পূর্ববর্তী ধারণাটি যে ম্যান পৃষ্ঠায় প্রদত্ত কারণটি ন্যায়সঙ্গত হয়েছে তা মোকাবেলা করার জন্য আপনাকে প্রত্যাশা করছি।
j_random_hacker

49
আমার বক্তব্যটি হ'ল ম্যান পেজে দেওয়া ন্যায়সঙ্গততা কোনও অর্থবোধ করে না, যেহেতু বরাদ্দ () হ'ল কোশার হিসাবে বিবেচিত অন্যান্য জিনিসগুলির (স্থানীয় অ্যারে বা পুনরুক্তি ফাংশন) হিসাবে ঠিক "খারাপ"।
j_random_hacker

39
@ নিনজালজ: অত্যন্ত অভিজ্ঞ সি / সি ++ প্রোগ্রামারদের দ্বারা নয়, তবে আমি মনে করি যে অনেক লোক যারা ভয় পান alloca()তাদের স্থানীয় অ্যারে বা পুনরূদ্ধার সমান ভয় থাকে না (আসলে অনেক লোক যারা চিৎকার alloca()করবে তারা পুনরাবৃত্তির প্রশংসা করবে কারণ এটি "মার্জিত দেখায়") । আমি শন এর পরামর্শের সাথে একমত ("বরাদ্দ (ছোট বরাদ্দের জন্য জরিমানা")) তবে আমি এই মানসিকতার সাথে একমত নই যে বরাদ্দকে () এর মধ্যে 3 এর মধ্যে অনন্যরূপে খারাপ বলে মনে করে - এগুলিও সমান বিপজ্জনক!
j_random_hacker

35
দ্রষ্টব্য: লিনাক্সের "আশাবাদী" মেমরি বরাদ্দের কৌশলটি দেওয়া, আপনি খুব সম্ভবত হিপ-ক্লান্তি ব্যর্থতার কোনও ইঙ্গিত পাবেন না ... পরিবর্তে malloc () আপনাকে একটি দুর্দান্ত নন-নুল পয়েন্টার ফিরিয়ে দেবে, এবং তারপরে আপনি যখন বাস্তবে চেষ্টা করবেন এটি যে ঠিকানাতে নির্দেশ করে সেখানে অ্যাক্সেস করুন, আপনার প্রক্রিয়া (বা অন্য কোনও প্রক্রিয়া, অনির্দেশ্য) ওওএম-ঘাতক দ্বারা নিহত হবে। অবশ্যই এটি প্রতি সি / সি ++ ইস্যুর পরিবর্তে লিনাক্সের একটি "বৈশিষ্ট্য", তবে বরাদ্দ () বা ম্যালোক () "নিরাপদ" কিনা তা নিয়ে বিতর্ক করার সময় এটি মনে রাখা উচিত। :)
জেরেমি ফ্রাইজনার

209

আমার কাছে সবচেয়ে স্মরণীয় ত্রুটিগুলির মধ্যে একটি হ'ল ব্যবহৃত ইনলাইন ফাংশনটি করানো হয়েছিল alloca। এটি প্রোগ্রামের সঞ্চালনের এলোমেলো পয়েন্টগুলিতে স্ট্যাকের ওভারফ্লো হিসাবে প্রকাশিত হয়েছিল (কারণ এটি স্ট্যাকের উপরে বরাদ্দ দেয়)।

শিরোলেখ ফাইলটিতে:

void DoSomething() {
   wchar_t* pStr = alloca(100);
   //......
}

বাস্তবায়ন ফাইলে:

void Process() {
   for (i = 0; i < 1000000; i++) {
     DoSomething();
   }
}

তাই যা ঘটেছিল তা সংকলক ইনিল্যান্ডড DoSomethingফাংশন এবং সমস্ত স্ট্যাক বরাদ্দ হচ্ছিল Process()ফাংশনের অভ্যন্তরে এবং এইভাবে স্ট্যাকটি উড়িয়ে দেওয়া। আমার প্রতিরক্ষার ক্ষেত্রে (এবং আমি সেই সমস্যাটিই খুঁজে পাইনি; যখন আমি এটি ঠিক করতে পারি না তখন আমাকে সিনিয়র বিকাশকারীদের কাছে গিয়ে কান্নাকাটি করতে হয়েছিল), এটি সোজা ছিল না alloca, এটি এটিএটিএল স্ট্রিংয়ের একটি রূপান্তর ছিল was ম্যাক্রো।

সুতরাং পাঠটি হ'ল - এমন allocaফাংশনগুলিতে ব্যবহার করবেন না যা আপনার মনে হয় in


91
মজাদার. কিন্তু এটি কি সংকলক বাগ হিসাবে যোগ্যতা অর্জন করবে না? সর্বোপরি, ইনলাইনিং কোডটির আচরণ পরিবর্তন করে (এটি বরাদ্দ ব্যবহার করে বরাদ্দকৃত স্থানটি মুক্ত করতে বিলম্ব করে)।
sleske

60
স্পষ্টতই, কমপক্ষে জিসিসি এটিকে বিবেচনায় নেবে: "নোট করুন যে কোনও ফাংশন সংজ্ঞায় নির্দিষ্ট ব্যবহারগুলি এটি ইনলাইন প্রতিস্থাপনের জন্য অনুপযুক্ত করে তুলতে পারে these এই ব্যবহারগুলির মধ্যে রয়েছে: ভারার্গ ব্যবহার, বরাদ্দ ব্যবহার, [...]"। gcc.gnu.org/onlinesocs/gcc/Inline.html
sleske

135
আপনি কি সংকলন ধূমপান ছিল?
টমাস এডিং

22
আমি যেটা বুঝতে পারি না তা হল যে সংকলক সাবস্কোপে বরাদ্দ কমবেশি "মুক্তি" পেয়েছে তা নির্ধারণ করার সুযোগটি কেন ভাল ব্যবহার করে না: স্ট্যাক পয়েন্টারটি স্কোপে প্রবেশের আগে তার বিন্দুতে ফিরে আসতে পারে, যেমন করা হয় তখন তার মতো ফাংশন থেকে ফিরে (না পারে?)
মোয়ালা

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

75

পুরানো প্রশ্ন কিন্তু কেউ উল্লেখ করেন নি যে এটি পরিবর্তনশীল দৈর্ঘ্যের অ্যারে দ্বারা প্রতিস্থাপন করা উচিত।

char arr[size];

পরিবর্তে

char *arr=alloca(size);

এটি স্ট্যান্ডার্ড সি 99 এ রয়েছে এবং অনেক সংকলকগুলিতে সংকলক এক্সটেনশন হিসাবে বিদ্যমান।


5
আর্থার উলফেল্টের উত্তরের মন্তব্যে এটি জোনাথন লেফলার উল্লেখ করেছেন।
নিনজাল্জ

2
প্রকৃতপক্ষে, তবে এটি এটি সহজেই কীভাবে মিস হয়েছে তাও দেখায়, যেমন পোস্টের আগে সমস্ত প্রতিক্রিয়াগুলি পড়েও আমি এটি দেখিনি।
প্যাট্রিক Schlüter

6
একটি নোট - সেগুলি পরিবর্তনশীল দৈর্ঘ্যের অ্যারে, গতিশীল অ্যারে নয়। আধুনিকগুলি পুনরায় আকারযুক্ত এবং সাধারণত গাদাতে প্রয়োগ করা হয়।
টিম Čas

1
কিছু সি ++ সংকলন ভিজ্যুয়াল স্টুডিও 2015 এর একই সমস্যা রয়েছে।
আহকক্স

2
লিনাস টর্ভাল্ডস লিনাক্স কার্নেলের ভিএলএল পছন্দ করে না । সংস্করণ হিসাবে 4.20 লিনাক্স প্রায় VLA মুক্ত হওয়া উচিত।
ক্রিশ্চিয়ান সিউপিতু

60

যদি আপনি একটি স্ট্যান্ডার্ড লোকাল ভেরিয়েবল ব্যবহার করতে না পারেন তবে বরাদ্দ () খুব কার্যকর কারণ রানটাইমের সময় এর আকার নির্ধারণ করা দরকার এবং আপনি নিশ্চয়তা দিতে পারবেন যে বরাদ্দ () থেকে আপনি যে পয়েন্টারটি পেয়েছেন তা এই ফাংশনটি ফেরার পরে কখনও ব্যবহার করা হবে না

আপনি মোটামুটি নিরাপদে থাকতে পারেন যদি আপনি

  • পয়েন্টার বা এতে থাকা কোনও কিছু ফিরিয়ে দেবে না।
  • স্তূপে বরাদ্দকৃত কোনও কাঠামোর মধ্যে পয়েন্টারটি সঞ্চয় করবেন না
  • অন্য কোনও থ্রেডকে পয়েন্টার ব্যবহার করতে দেবেন না

আসল বিপদটি এই সুযোগটি থেকে আসে যে পরে আর কেউ এই শর্তগুলি লঙ্ঘন করবে। এটি মনে রেখে এটি বাফারগুলিকে ফাংশনে ফর্ম্যাট করে ফাংশনগুলিতে পাস করার জন্য এটি দুর্দান্ত :)


12
সি 99 এর ভিএলএ (ভেরিয়েবল দৈর্ঘ্যের অ্যারে) বৈশিষ্ট্যটি স্পষ্টভাবে ব্যবহারের জন্য বরাদ্দ () প্রয়োজন না করে গতিশীল আকারের স্থানীয় ভেরিয়েবল সমর্থন করে।
জোনাথন লেফলার


1
তবে পয়েন্টারগুলি স্থানীয় ভেরিয়েবলগুলিতে পরিচালনা করা থেকে আলাদা নয়। তারা পাশাপাশি বোকা হতে পারে ...
glglgl

2
@ জোনাথন লেফলার একটি জিনিস যা আপনি বরাদ্দ দিয়ে করতে পারেন তবে আপনি ভিএলএর সাথে করতে পারবেন না তাদের সাথে সীমাবদ্ধ কীওয়ার্ডটি ব্যবহার করা হচ্ছে। এটির মতো: ভাসমান * সীমাবদ্ধ ভারী_যুক্ত_আর = বরাদ্দ (আকারে (ভাসা) * আকার); ভারী_যুক্ত_আর [আকার] এর পরিবর্তে ভাসা। এটি আকার সংকলনের ধ্রুবক হলেও কিছু সংকলককে (আমার ক্ষেত্রে জিসিসি 4.8) অ্যাসেম্বলি অনুকূল করতে সহায়তা করতে পারে। এটি সম্পর্কে আমার প্রশ্নটি দেখুন:
স্ট্যাকওভারফ্লো / প্রশ্নগুলি / ১১০২646464৩

@ জোনাথনলফলার একটি ভিএলএ এটির মধ্যে থাকা ব্লকের স্থানীয়। অন্যদিকে, alloca()মেমরিটি বরাদ্দ করে যা ফাংশন শেষ হওয়া অবধি স্থায়ী হয়। এর অর্থ হ'ল ভিএলএর কোনও সরল, সুবিধাজনক অনুবাদ নেই f() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }। আপনি যদি ভাবেন যে allocaভিএলএর ব্যবহারের ব্যবহারগুলি স্বয়ংক্রিয়ভাবে অনুবাদ করা সম্ভব তবে কীভাবে বর্ণনা করার জন্য একটি মন্তব্যের চেয়ে বেশি প্রয়োজন, আমি এটি একটি প্রশ্ন করতে পারি।
পাস্কেল কুয়াক

40

এই নিউজগ্রুপ পোস্টে যেমন উল্লেখ করা হয়েছে , ব্যবহারকে allocaকঠিন ও বিপজ্জনক বলে বিবেচনা করার কয়েকটি কারণ রয়েছে :

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

24
আমি এই লিঙ্কটিতে যা দেখেছি যা এই পৃষ্ঠায় অন্য কোথাও নেই তা হ'ল যে ফাংশনটি ব্যবহার করে তার alloca()জন্য স্ট্যাক পয়েন্টার এবং ফ্রেম পয়েন্টার ধরে রাখার জন্য পৃথক রেজিস্টার প্রয়োজন। X86 সিপিইউ> = 386-এ, স্ট্যাক পয়েন্টারটি ESPউভয়ের জন্য ব্যবহার করা যেতে পারে, নিঃসরণ করা হয় EBP- যদি না alloca()ব্যবহৃত হয়।
j_random_hacker

10
এই পৃষ্ঠায় আরেকটি ভাল পয়েন্ট হ'ল কম্পাইলারের কোড জেনারেটর যদি এটি একটি বিশেষ কেস হিসাবে পরিচালনা না f(42, alloca(10), 43);করে তবে স্ট্যাক পয়েন্টারটি কমপক্ষে একটি তর্ক যুক্ত alloca() হওয়ার পরে এটি সামঞ্জস্য হওয়ার সম্ভাবনার কারণে ক্রাশ হতে পারে ।
j_random_hacker

3
লিঙ্কযুক্ত পোস্টটি জন লেভিনের দ্বারা লিখিত হয়েছে বলে মনে হয় - যে "লিঙ্কারস এবং লোডারস" লিখেছিল এই ছেলেটি, তিনি যা বলেন তা আমি বিশ্বাস করব।
ব্যবহারকারী318904

3
লিঙ্কযুক্ত পোস্টটি জন লেভিনের একটি পোস্টের জবাব
উ। উইলকক্স

6
মনে রাখবেন, ১৯৯১ সাল থেকে অনেক কিছু পরিবর্তিত হয়েছে All সমস্ত আধুনিক সি সংকলক (এমনকি ২০০৯ সালেও) একটি বিশেষ কেস হিসাবে বরাদ্দ পরিচালনা করতে হবে; এটি একটি সাধারণ ক্রিয়াকলাপের চেয়ে স্বতন্ত্র এবং এটি কোনও ফাংশনকে কলও নাও করতে পারে। সুতরাং, বরাদ্দ-ইন-প্যারামিটার ইস্যু (যা ১৯ 1970০ এর দশকে কেএন্ডআর সিতে উদ্ভূত হয়েছিল) এখন কোনও সমস্যা হওয়া উচিত নয়। টনি ডি এর উত্তরে আমি করা মন্তব্যে আরও বিশদ
গ্রেগগো

26

একটি সমস্যা হ'ল এটি আদর্শ নয়, যদিও এটি ব্যাপকভাবে সমর্থিত। অন্যান্য জিনিস সমান হচ্ছে, আমি সর্বদা একটি সাধারণ সংকলক এক্সটেনশনের পরিবর্তে একটি স্ট্যান্ডার্ড ফাংশন ব্যবহার করব।


21

এখনও বরাদ্দ ব্যবহার নিরুত্সাহিত হয়, কেন?

আমি এ জাতীয় perceiveকমত্য বুঝতে পারছি না। প্রচুর দৃ pros় পেশাদার; কয়েকটি কনস:

  • C99 পরিবর্তনশীল দৈর্ঘ্যের অ্যারে সরবরাহ করে, যা প্রায়শই স্থির-দৈর্ঘ্যের অ্যারে এবং স্বজ্ঞাত সামগ্রিক সাথে স্বরলিপি হিসাবে আরও সুসংগত হিসাবে ব্যবহার করা হত
  • অনেক সিস্টেমে স্ট্যাকের জন্য স্তূপের চেয়ে কম সামগ্রিক মেমরি / ঠিকানা-স্থান উপলব্ধ থাকে যা মেমরির ক্লান্তির জন্য প্রোগ্রামটিকে কিছুটা বেশি সংবেদনশীল করে তোলে (স্ট্যাক ওভারফ্লো মাধ্যমে): এটি ভাল বা খারাপ জিনিস হিসাবে দেখা যেতে পারে - এক স্তূপটি স্বয়ংক্রিয়ভাবে বৃদ্ধি না হওয়ার কারণগুলি হ'ল নিয়ন্ত্রণের বাইরে থাকা প্রোগ্রামগুলিকে পুরো মেশিনে যতটা বিরূপ প্রভাব ফেলতে পারে তা প্রতিরোধ করা
  • যখন আরও স্থানীয় স্কোপ (যেমন একটি whileবা forলুপ) বা বিভিন্ন স্কোপে ব্যবহৃত হয়, তখন মেমরিটি পুনরাবৃত্তি / স্কোপ অনুযায়ী জমা হয় এবং ফাংশনটি বের না হওয়া অবধি প্রকাশ হয় না: এটি একটি নিয়ন্ত্রণ কাঠামোর স্কোপে সংজ্ঞায়িত সাধারণ ভেরিয়েবলের সাথে বিপরীতে থাকে (যেমন: for {int i = 0; i < 2; ++i) { X }জমা হবেalloca এক্স-এ অনুরোধ করা -যুক্ত মেমরি তবে স্থির আকারের অ্যারেগুলির জন্য মেমরিটি পুনরাবৃত্তির জন্য পুনর্ব্যবহার করা হবে)।
  • আধুনিক সংকলক সাধারণত inlineকল করে না alloca, তবে আপনি যদি তাদের জোর করে থাকেন তবে allocaতা কলারের প্রসঙ্গে ঘটবে (যেমন কলার ফিরে না আসা পর্যন্ত স্ট্যাকটি প্রকাশ করা হবে না)
  • একটি দীর্ঘ সময় পূর্বে allocaএকটি বহনযোগ্য বৈশিষ্ট্য / হ্যাক থেকে একটি স্ট্যান্ডার্ডাইজড এক্সটেনশনে স্থানান্তরিত হয়েছে তবে কিছু নেতিবাচক উপলব্ধি অবিরত থাকতে পারে
  • আজীবন ফাংশন স্কোপটিতে আবদ্ধ, যা প্রোগ্রামারের mallocস্পষ্ট নিয়ন্ত্রণের চেয়ে ভালতর বা নাও পারা যায়
  • mallocডিওলোকেশন সম্পর্কে চিন্তাভাবনা করতে উত্সাহিত করে - যদি এটি একটি মোড়কের ফাংশন (যেমন WonderfulObject_DestructorFree(ptr)) দ্বারা পরিচালিত হয় , তবে ফাংশনটি ক্লায়েন্টের সুস্পষ্ট পরিবর্তন ব্যতিরেকে ক্লিন আপ অপারেশনগুলির (যেমন ফাইল বর্ণনাকারীদের বন্ধকরণ, অভ্যন্তরীণ পয়েন্টারগুলি মুক্ত করা বা কিছু লগিং করা) কার্যকর করার জন্য একটি বিন্দু সরবরাহ করে কোড: কখনও কখনও ধারাবাহিকভাবে গ্রহণ করা এটি একটি দুর্দান্ত মডেল
    • প্রোগ্রামিংয়ের এই সিউডো-ওও স্টাইলে, এমন কিছু হওয়া স্বাভাবিক WonderfulObject* p = WonderfulObject_AllocConstructor();that's এটি সম্ভব যখন "কনস্ট্রাক্টর" কোনও ফাংশন রিটার্নিং- mallocএড মেমরি করে (যেমন ফাংশনটি সঞ্চিত মানটি ফিরিয়ে দেওয়ার পরে মেমরিটি বরাদ্দ থাকে p) তবে তা নয় যদি "কনস্ট্রাক্টর" ব্যবহার করেalloca
      • এর ম্যাক্রো সংস্করণ এটি WonderfulObject_AllocConstructorঅর্জন করতে পারে তবে "ম্যাক্রোরা দুষ্ট" যে তারা একে অপরের সাথে এবং নন-ম্যাক্রো কোডের সাথে দ্বন্দ্ব করতে পারে এবং অনিচ্ছাকৃত বিকল্পগুলি তৈরি করতে পারে এবং ফলস্বরূপ নির্ণয় করতে অসুবিধাজনিত সমস্যা
    • অনুপস্থিত freeক্রিয়াকলাপগুলি ভালগ্র্যান্ড, পিউরিফাই ইত্যাদি দ্বারা সনাক্ত করা যায় তবে অনুপস্থিত "ডেস্ট্রাক্টর" কলগুলি সর্বদা সনাক্ত করা যায় না - উদ্দেশ্যযুক্ত ব্যবহারের প্রয়োগের ক্ষেত্রে একটি অত্যন্ত সুস্পষ্ট সুবিধা; কিছু alloca()বাস্তবায়ন (যেমন জিসিসির) একটি ইনলাইনড ম্যাক্রো ব্যবহার করে alloca(), সুতরাং মেমোরি-ব্যবহার ডায়াগনস্টিক লাইব্রেরির রানটাইম প্রতিস্থাপন এটি malloc/ realloc/ free(যেমন বৈদ্যুতিক বেড়া) এর মতো সম্ভব নয়
  • কিছু বাস্তবায়নের সূক্ষ্ম সমস্যা রয়েছে: উদাহরণস্বরূপ, লিনাক্স ম্যানপেজ থেকে:

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


আমি জানি এই প্রশ্নটি সি ট্যাগ করা আছে, তবে একজন সি ++ প্রোগ্রামার হিসাবে আমি ভেবেছিলাম যে এর সম্ভাব্য ইউটিলিটি চিত্রিত করতে আমি সি ++ ব্যবহার করব alloca: নীচের কোডটি (এবং এখানে আদর্শে ) একটি ভেক্টরকে বিভিন্ন আকারের পলিমারফিক ধরণের বরাদ্দযুক্ত ট্র্যাকিং তৈরি করে (সহ) আজীবন ফাংশন রিটার্নে আবদ্ধ) বরং বরাদ্দ গাদা।

#include <alloca.h>
#include <iostream>
#include <vector>

struct Base
{
    virtual ~Base() { }
    virtual int to_int() const = 0;
};

struct Integer : Base
{
    Integer(int n) : n_(n) { }
    int to_int() const { return n_; }
    int n_;
};

struct Double : Base
{
    Double(double n) : n_(n) { }
    int to_int() const { return -n_; }
    double n_;
};

inline Base* factory(double d) __attribute__((always_inline));

inline Base* factory(double d)
{
    if ((double)(int)d != d)
        return new (alloca(sizeof(Double))) Double(d);
    else
        return new (alloca(sizeof(Integer))) Integer(d);
}

int main()
{
    std::vector<Base*> numbers;
    numbers.push_back(factory(29.3));
    numbers.push_back(factory(29));
    numbers.push_back(factory(7.1));
    numbers.push_back(factory(2));
    numbers.push_back(factory(231.0));
    for (std::vector<Base*>::const_iterator i = numbers.begin();
         i != numbers.end(); ++i)
    {
        std::cout << *i << ' ' << (*i)->to_int() << '\n';
        (*i)->~Base();   // optionally / else Undefined Behaviour iff the
                         // program depends on side effects of destructor
    }
}

নং +1 কারণ বিভিন্ন ধরণের পরিচালনা করার
ফিশিয়্যাল আইডিসিক্র্যাটিক পদ্ধতি

@ আইনপোকলুম: বেশ যে গভীরভাবে আলোকিত হচ্ছে ... ধন্যবাদ
টনি ডেলরয়

1
আমাকে পুনঃব্যবহার করা যাক: এটি একটি খুব ভাল উত্তর। আমি মনে করি আপনি যেখানে লোকেরা এক ধরণের পাল্টা-প্যাটার্ন ব্যবহার করেন তা আমি মনে করি।
einpoklum

লিনাক্স ম্যানপেজের মন্তব্যটি খুব পুরানো এবং, আমি বেশ নিশ্চিত, অপ্রচলিত। সমস্ত আধুনিক সংকলক জানেন যে বরাদ্দ () কী, এবং তাদের জুতার উপরের মতো ভ্রমণ করবে না। পুরানো কেএন্ডআর সি-তে, (1) সমস্ত ফাংশন ব্যবহৃত ফ্রেম পয়েন্টার (2) সমস্ত ফাংশন কলগুলি ছিল {স্ট্যাকের উপর চাপগুলি} {কল ফানক} {যুক্ত # এন, এসপি}} বরাদ্দ একটি lib ফাংশন যা কেবল স্ট্যাক আপকে ধাক্কা দেবে, সংকলক এমনকি ঘটনার বিষয়েও জানত না। (1) এবং (2) আর সত্য নয় তাই বরাদ্দাগুলি সেভাবে কাজ করতে পারে না (এখন এটি একটি স্বতন্ত্র)। পুরানো সিতে, চাপ দেওয়ার মধ্যে মাঝখানে এলোকা কল করা স্পষ্টতই সেই অনুমানগুলিও ভেঙে দেবে।
গ্রেগগো

4
উদাহরণটি সম্পর্কে, আমি সাধারণত এমন কিছু সম্পর্কে উদ্বিগ্ন থাকি যা স্মৃতি দুর্নীতি এড়ানোর জন্য সর্বদা_ইনলাইন প্রয়োজন ....
গ্রেগগো

14

অন্যান্য উত্তরগুলির সমস্ত সঠিক। তবে, আপনি যে জিনিসটি ব্যবহার করে বরাদ্দ করতে চান তা alloca()যদি যুক্তিসঙ্গতভাবে ছোট হয় তবে আমি মনে করি এটি একটি ভাল প্রযুক্তি যা ব্যবহার করা malloc()বা অন্যথায় ব্যবহারের চেয়ে দ্রুত এবং বেশি সুবিধাজনক ।

অন্য কথায়, alloca( 0x00ffffff )ঠিক যতটা, বিপজ্জনক এবং কারণ ওভারফ্লো সম্ভবত char hugeArray[ 0x00ffffff ];নেই। সাবধান এবং যুক্তিসঙ্গত হন এবং আপনি ভাল থাকবেন।


12

এই "পুরানো" প্রশ্নের অনেক আকর্ষণীয় উত্তর, এমনকি কিছু তুলনামূলকভাবে নতুন উত্তর, তবে আমি এর উল্লেখ করার মতো কোনও উত্তর পাই নি ....

সঠিকভাবে এবং যত্ন সহকারে ব্যবহৃত হলে, alloca() সামান্য ব্যবহারযোগ্য (সম্ভবত অ্যাপ্লিকেশন-প্রশস্ত) ছোট ভেরিয়েবল-দৈর্ঘ্যের বরাদ্দগুলি হ্যান্ডেল করার জন্য (বা C99 ভিএলএগুলি, যেখানে উপলব্ধ) হ'ল স্থির দৈর্ঘ্যের বড় আকারের স্থানীয় অ্যারে ব্যবহার করে অন্যথায় সমমানের প্রয়োগের চেয়ে কম সামগ্রিক স্ট্যাকের বৃদ্ধি ঘটাতে পারে । আপনি যদি যত্ন সহকারে এটি ব্যবহার করেন তবে আপনার স্ট্যাকের পক্ষে ভালalloca() হতে পারে ।

আমি সেই উদ্ধৃতিটি পেয়েছি .... ঠিক আছে, আমি সেই উদ্ধৃতিটি তৈরি করেছিলাম। তবে সত্যিই, এটি সম্পর্কে চিন্তা করুন ....

@ জ_আরন্ডম_হ্যাকার অন্যান্য মন্তব্যে তার মন্তব্যে একেবারেই সঠিক: alloca()বড় আকারের স্থানীয় অ্যারে ব্যবহারের পক্ষে এড়ানো আপনার প্রোগ্রামটিকে স্ট্যাক ওভারফ্লো থেকে নিরাপদ করে না (যদি না আপনার সংকলকটি ফাংশনগুলির ইনলাইনিংয়ের অনুমতি দেওয়ার ক্ষেত্রে যথেষ্ট বয়স্ক না হয় তবে আপনার alloca()ক্ষেত্রে যা করা উচিত আপগ্রেড করুন, বা যদি না আপনি alloca()লুপের অভ্যন্তরে ব্যবহার করেন তবে এক্ষেত্রে আপনার উচিত ... alloca()লুপগুলির অভ্যন্তরে ব্যবহার করা উচিত নয় )।

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

alloca() (বা ভিএলএএস) কাজের জন্য সঠিক উপকরণ হতে পারে।

আমি আবার সময় এবং সময় দেখেছি যেখানে কোনও প্রোগ্রামার স্ট্যাক-বরাদ্দ বাফারটিকে "কোনও সম্ভাব্য কেস পরিচালনা করার পক্ষে যথেষ্ট বড়" করে তোলে। গভীরভাবে নেস্টেড কল ট্রিতে, সেই (বিরোধী?) প্যাটার্নটির বারবার ব্যবহার অতিরঞ্জিত স্ট্যাকের ব্যবহারের দিকে নিয়ে যায়। (কল ট্রিটিকে ২০ স্তর উচ্চতর কল্পনা করুন, যেখানে প্রতিটি স্তরে বিভিন্ন কারণে, ফাংশনটি অন্ধভাবে 1024 বাইটের একটি বাফারকে "কেবল নিরাপদ হতে" বরাদ্দ করে) যখন সাধারণত এটি কেবল তাদের 16 বা তার কম ব্যবহার করবে এবং কেবল খুব বিরল ক্ষেত্রে বেশি ব্যবহার করতে পারে)) বিকল্প হিসাবে ব্যবহার করাalloca()বা ভিএলএগুলি এবং অযথা স্ট্যাকের বোঝা এড়াতে আপনার ফাংশনটির যতটা স্ট্যাক স্পেস প্রয়োজন তা বরাদ্দ করুন। আশা করা যায় যে যখন কল ট্রিে একটি ফাংশনকে স্বাভাবিকের চেয়ে বড় বরাদ্দের প্রয়োজন হয়, কল ট্রিতে অন্যরা তাদের সাধারণ ছোট বরাদ্দগুলি এখনও ব্যবহার করছেন এবং সামগ্রিক প্রয়োগ স্ট্যাকের ব্যবহারটি যদি প্রতিটি ফাংশন অন্ধভাবে একটি স্থানীয় বাফারকে অতিরিক্ত বরাদ্দ করে দেয় তবে তার চেয়ে কম ।

আপনি যদি ব্যবহার করতে চান তবে alloca()...

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


আমি এই বিষয়টির সাথে একমত এর বিপজ্জনক alloca()সত্য, তবে একই সাথে মেমরি ফুটো সম্পর্কে বলা যেতে পারে malloc()(কেন তখন একজন জিসি ব্যবহার করবেন না? কেউ তর্ক করতে পারে)। alloca()যত্ন সহ যখন ব্যবহার করা হয় তখন স্ট্যাকের আকার হ্রাস করতে সত্যই কার্যকর হতে পারে।
ফিলিপ টোনলো

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

সিডনোট: "একটি স্থির বাফার ব্যবহার করে [MAX_SIZE]" উদাহরণটি কেন ওভারকমিট মেমরি নীতিটি এত ভাল কাজ করে তা হাইলাইট করে। প্রোগ্রামগুলি মেমরি বরাদ্দ করে তাদের বাফার দৈর্ঘ্যের সীমা ছাড়া তারা কখনও স্পর্শ করতে পারে না। সুতরাং এটি ঠিক আছে যে লিনাক্স (এবং অন্যান্য ওএসের) মেমোরির প্রথম পৃষ্ঠা ব্যবহার না করা (ম্যালোক'ডের বিপরীতে) না হওয়া পর্যন্ত আসলে কোনও পৃষ্ঠা নির্ধারণ করে না। যদি বাফার এক পৃষ্ঠার চেয়ে বড় হয় তবে প্রোগ্রামটি কেবল প্রথম পৃষ্ঠাটি ব্যবহার করতে পারে এবং বাকি শারীরিক মেমরিটি নষ্ট করে না।
ক্যাটাস্টিক ভয়েজ

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

11

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

আপনি এই এসএইচ ব্যতিক্রমটি ধরতে পারেন এবং স্ট্যাকটিকে পুনরায় সেট করতে এবং আপনার আনন্দময় পথে চালিয়ে যেতে _ রিসেটটকোফ্লুউ কল করতে পারেন। এটি আদর্শ নয় তবে জিনিসটি ফ্যানে আঘাত করলে কমপক্ষে কিছু ভুল হয়ে গেছে তা জানার এটি অন্য একটি প্রক্রিয়া। * নিক্স এর মতো কিছু থাকতে পারে যা আমি অবগত নই।

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

এছাড়াও, মেমরি ফাঁসের অনুমতি না দেওয়ার পাশাপাশি বরাদ্দ মেমরির খণ্ডন ঘটায় না যা বেশ গুরুত্বপূর্ণ। আমি মনে করি না আপনি যদি বুদ্ধিমানভাবে এটি ব্যবহার করেন তবে বরাদ্দটি খারাপ অভ্যাস বলে মনে হচ্ছে যা মূলত সবকিছুর জন্য সত্য। :-)


সমস্যাটি হ'ল এটি alloca()এত জায়গার দাবি করতে পারে যে স্ট্যাকপয়েন্টারটি স্তূপে অবতরণ করে। এটির সাহায্যে, এমন আক্রমণকারী যিনি আকারটি নিয়ন্ত্রণ করতে পারেন alloca()এবং যে ডেটা সেই বাফারে যায় সেগুলি হিপটিকে ওভাররাইট করতে পারে (যা খুব খারাপ)।
12431234123412341234123

এসইএইচ একটি উইন্ডোজ-কেবল জিনিস। এটি দুর্দান্ত যদি আপনি কেবলমাত্র উইন্ডোজে আপনার কোডটি চালনার বিষয়ে চিন্তা করেন তবে যদি আপনার কোডটি ক্রস প্ল্যাটফর্মের প্রয়োজন হয় (বা আপনি যদি কেবল একটি উইন্ডোজ প্ল্যাটফর্মের সাথে চলমান কোড লিখে থাকেন) তবে আপনি থাকার উপর নির্ভর করতে পারবেন না Seh।
জর্জ

10

বরাদ্দ () দুর্দান্ত এবং দক্ষ ... তবে এটি খুব গভীরভাবে ভেঙে গেছে।

  • ভাঙ্গা সুযোগ আচরণ (ব্লক স্কোপের পরিবর্তে ফাংশন স্কোপ)
  • malloc সঙ্গে inconsistant ব্যবহার করুন ( alloca () -ted পয়েন্টার মুক্ত করা উচিত নয়, অত: পর আপনি ট্র্যাক করতে যেখানে আপনি পয়েন্টার থেকে আসছে আছে বিনামূল্যে () শুধুমাত্র যাদের সাথে আপনি পেয়েছিলাম যদি malloc () )
  • আপনি যখন ইনলাইনিং ব্যবহার করেন তখন খারাপ আচরণ (স্কোপ কখনও কখনও কলার ইনলাইনড থাকে বা না তার উপর নির্ভর করে কলার ফাংশনে যায়)।
  • কোনও স্ট্যাকের বাউন্ডারি চেক নেই
  • ব্যর্থতার ক্ষেত্রে অপরিজ্ঞাত আচরণ (ম্যালোকের মতো নল ফেরায় না ... এবং ব্যর্থতার অর্থ কী তা স্ট্যাকের সীমানা যাচাই করে না ...)
  • আনসি মান না

বেশিরভাগ ক্ষেত্রে আপনি স্থানীয় ভেরিয়েবল এবং বৃহত্তর আকার ব্যবহার করে এটি প্রতিস্থাপন করতে পারেন। যদি এটি বড় আকারের বস্তুর জন্য ব্যবহার করা হয় তবে এগুলিকে গাদাতে রাখা সাধারণত নিরাপদ ধারণা।

আপনার যদি সত্যিই এটির প্রয়োজন হয় আপনি ভিএলএ ব্যবহার করতে পারেন (সি ++ তে কোনও ভ্লা নেই, খুব খারাপ)। স্কোপ আচরণ এবং ধারাবাহিকতা সম্পর্কে তারা বরাদ্দ () এর চেয়ে অনেক ভাল। আমি দেখতে পাচ্ছি ভিএলএ হ'ল এক ধরণের বরাদ্দ () ডান বানানো made

অবশ্যই প্রয়োজনীয় স্থানটির একটি বৃহত্তর ব্যবহার করে একটি স্থানীয় কাঠামো বা অ্যারে এখনও আরও ভাল এবং আপনার যদি প্লেইন ম্যালোক () ব্যবহার করে এমন মজোরান্ট হিপ বরাদ্দ না পান তবে সম্ভবত বুদ্ধিমান। আমি এমন কোনও বুদ্ধিমান ব্যবহারের ঘটনা দেখতে পাচ্ছি না যেখানে আপনার সত্যিই বরাদ্দ () বা ভিএলএ প্রয়োজন।



কেবল নামের সুযোগ রয়েছে। allocaএকটি নাম তৈরি করে না, কেবল একটি মেমরি রেঞ্জ, যার জীবনকাল রয়েছে
কৌতূহলী

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

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

2
@ সুপের্যাট - আমিও তাই চাই যে কারণে (এবং আরো) জন্য, আমি একটি বিমূর্ততা স্তর (বেশিরভাগই ম্যাক্রো এবং ইনলাইন ফাংশন) যাতে আমি কখনো কল না ব্যবহার allocaবা mallocবা freeসরাসরি। আমি মত জিনিস {stack|heap}_alloc_{bytes,items,struct,varstruct}এবং {stack|heap}_dealloc। সুতরাং, heap_deallocকেবল কল করুন freeএবং stack_deallocএটি কোনও অপশন নয়। এইভাবে, স্ট্যাক বরাদ্দগুলি সহজেই গাদা বরাদ্দে ডাউনগ্রেড করা যায় এবং উদ্দেশ্যগুলি আরও স্পষ্ট হয়।
টড লেহম্যান

9

কারণটা এখানে:

char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;

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

কার্যত সমস্ত কোড allocaএবং / অথবা C99 ভ্লাস ব্যবহার করে এমন গুরুতর বাগ রয়েছে যা ক্র্যাশ হতে পারে (যদি আপনি ভাগ্যবান হন) বা সুযোগ সুবিধার সমঝোতা (যদি আপনি এত ভাগ্যবান না হন)।


1
বিশ্বের কখনই জানতে পারে. :( এটি বলেছিল, আমি আশা করছি যে আমার সম্পর্কে আমার একটি প্রশ্ন আপনি পরিষ্কার করতে পারবেন alloca। আপনি বলেছিলেন যে এটি ব্যবহার করা প্রায় সমস্ত কোডেই একটি বাগ রয়েছে, তবে আমি এটি ব্যবহার করার পরিকল্পনা করছিলাম; আমি সাধারণত এ জাতীয় দাবি উপেক্ষা করতাম তবে আসছি আপনার কাছ থেকে আমি করব না আমি একটি ভার্চুয়াল মেশিন লিখছি এবং আমি প্রচুর গতি বাড়ানোর কারণে গতিশীলতার পরিবর্তে স্ট্যাকের ফাংশন থেকে রক্ষা পাবে না এমন ভেরিয়েবলগুলি বরাদ্দ করতে চাই there একই কর্মক্ষমতা বৈশিষ্ট্য আছে এমন পদ্ধতির? আমি জানি আমি মেমরি পুলগুলির সাথে কাছে যেতে পারি, তবে এটি এখনও
এতটা

7
জেনে নিন কী বিপজ্জনক? এটি: *0 = 9;আশ্চর্যজনক !!! আমার ধারণা আমার কখনই পয়েন্টার ব্যবহার করা উচিত নয় (বা কমপক্ষে সেগুলি ডিফারেন্স করুন)। এর, অপেক্ষা করুন। আমি এটি পরীক্ষা করে দেখতে পারি এটি নাল কিনা। হুম। আমার ধারণা আমি যে মেমোরির মাধ্যমে বরাদ্দ করতে চাই তার আকারও পরীক্ষা করতে পারি alloca। অদ্ভুত মানুষ. রহস্যময়।
টমাস এডিং

7
*0=9;বৈধ নয় সি আপনি যে আকারে পাস করেছেন তা allocaপরীক্ষা করার জন্য এটি কিসের বিরুদ্ধে পরীক্ষা করবেন? সীমাটি জানার কোনও উপায় নেই এবং যদি আপনি এটি কেবলমাত্র একটি নির্দিষ্ট স্থিত ज्ञিত-নিরাপদ আকারের (উদাহরণস্বরূপ 8 কে) এর বিরুদ্ধে পরীক্ষা করতে যাচ্ছেন তবে আপনি কেবল স্ট্যাকের উপর একটি নির্দিষ্ট আকারের অ্যারে ব্যবহার করতে পারেন।
আর .. গীটহাব বন্ধ করুন ICE

7
আপনার "হয় আকারটি যথেষ্ট ছোট হিসাবে পরিচিত বা এটি ইনপুট-নির্ভর এবং এটি নির্বিচারে বৃহত্তর হতে পারে" হিসাবে সমস্যাটি আমি দেখতে পাচ্ছি যে এটি পুনরুক্তার জন্য ঠিক তীব্রভাবে প্রযোজ্য। একটি ব্যবহারিক আপস (উভয় ক্ষেত্রে) ধরে নেওয়া হয় যে আকারটি যদি small_constant * log(user_input)তখনই সীমাবদ্ধ থাকে তবে আমাদের সম্ভবত যথেষ্ট পরিমাণ স্মৃতি রয়েছে।
j_random_hacker

1
প্রকৃতপক্ষে, আপনি এমন একটি কেস সনাক্ত করেছেন যেখানে ভিএলএ / বরাদ্দ কার্যকর: পুনরাবৃত্তকৃত অ্যালগরিদম যেখানে কোনও কল ফ্রেমে প্রয়োজনীয় সর্বাধিক স্থান N এর মতো বড় হতে পারে তবে যেখানে সমস্ত পুনরাবৃত্তির স্তরে প্রয়োজনীয় স্থানের যোগফল N বা কিছু ফাংশন রয়েছে এন এর যে দ্রুত বৃদ্ধি হয় না।
আর .. গীটহাব বন্ধ করুন আইসিসি

9

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

উদাহরণস্বরূপ, সি কম্পাইলারদের দ্বারা একটি সাধারণ অপ্টিমাইজেশন হ'ল কোনও ফাংশনের মধ্যে ফ্রেম পয়েন্টার ব্যবহার বাদ দেওয়া, ফ্রেমের প্রবেশাধিকারগুলি স্ট্যাক পয়েন্টারের পরিবর্তে স্ট্যাক পয়েন্টারের তুলনায় তৈরি করা হয়; সুতরাং সাধারণ ব্যবহারের জন্য আরও একটি নিবন্ধ রয়েছে। তবে যদি ফাংশনটির মধ্যে বরাদ্দ আহ্বান করা হয় তবে এসপি এবং এফপি মধ্যে পার্থক্যটি ফাংশনের অংশের জন্য অজানা হতে পারে, সুতরাং এই অপ্টিমাইজেশনটি করা যায় না।

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

আপডেট: যেহেতু পরিবর্তনশীল দৈর্ঘ্যের স্থানীয় অ্যারেগুলিকে সি-তে যুক্ত করা হয়েছে, এবং যেহেতু এইগুলি প্রচলিত কোড-প্রজন্মের বিষয়গুলি বরাদ্দ হিসাবে সংকলকের সাথে সংযুক্ত করে, আমি দেখতে পাচ্ছি যে 'ব্যবহারের বিরলতা এবং ছায়াময় অবস্থা' অন্তর্নিহিত ব্যবস্থায় প্রযোজ্য নয়; তবে আমি এখনও সন্দেহ করব যে বরাদ্দ বা ভিএলএর কোনও একটির ব্যবহারের ফলে কোনও ফাংশনের মধ্যে কোড জেনারেশনের সাথে আপস করা যায় that আমি সংকলক ডিজাইনারদের থেকে কোন প্রতিক্রিয়া স্বাগত জানাই।


1
পরিবর্তনশীল দৈর্ঘ্যের অ্যারেগুলি কখনই সি ++ এ যুক্ত করা হয়নি।
নীড় ফ্রিডম্যান

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

> আমি এখনও সন্দেহ করব যে বরাদ্দ বা ভিএলএর কোনও একটির ব্যবহার কোড কোড তৈরির সাথে আপস করে I আরও স্ট্যাক মেমরি ধরে রাখার জন্য বা একটি রান-টাইম গণনা করা মাপ ইত্যাদির জন্য একটি লুপে বরাদ্দ বলা যেতে পারে etc. এটি ব্যবহার করা হয় না।
কাজ

8

এর মধ্যে একটি ক্ষতি allocaহ'ল এটি longjmpপুনরুদ্ধার করে।

এর অর্থ হল, আপনি যদি কোনও প্রসঙ্গটি সংরক্ষণ করেন setjmpতবে allocaকিছু স্মৃতি, তারপরে longjmpপ্রসঙ্গে আপনি allocaস্মৃতিটি হারাতে পারেন । স্ট্যাক পয়েন্টারটি যেখানে ছিল সেখানে ফিরে এসেছিল এবং সুতরাং মেমরিটি আর সংরক্ষিত নেই; যদি আপনি কোনও ফাংশন কল করেন বা অন্য কোনও কাজ করেন তবে আপনি allocaআসলটি ক্লোবার করবেন alloca

স্পষ্ট করে বলতে longjmpগেলে, আমি এখানে বিশেষভাবে যা উল্লেখ করছি তা এমন একটি পরিস্থিতি যার দ্বারা allocaসঞ্চালিত ফাংশনটি থেকে ফিরে ফিরে আসে না ! বরং, একটি ফাংশন এর সাথে প্রসঙ্গ সংরক্ষণ করে setjmp; তারপরে মেমরিটি বরাদ্দ করে allocaএবং অবশেষে সেই প্রসঙ্গে একটি লংজ্যাম্প সংঘটিত হয়। এই ফাংশনের allocaস্মৃতি সমস্ত মুক্ত হয় না; এটি সমস্ত স্মৃতি যে এটি থেকে বরাদ্দ setjmp। অবশ্যই, আমি একটি পর্যবেক্ষণ আচরণ সম্পর্কে বলছি; এ জাতীয় কোনও প্রয়োজনীয়তা allocaআমার জানা কোনও নথিভুক্ত নয় ।

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

ঘটনাচক্রে, এটি যদি এটি সেভাবে কাজ করে তবে ইচ্ছাকৃতভাবে বরাদ্দ করা মেমরিটি মুক্ত করার জন্য একটি প্রশংসনীয় ব্যবস্থা সরবরাহ করে alloca

আমি এটিকে বাগের মূল কারণ হিসাবে চালিয়েছি।


1
যদিও এটি করার কথা ছিল তা - longjmpএটি ফিরে যায় এবং এটি তৈরি করে তোলে যাতে স্ট্যাকের মধ্যে ঘটে যাওয়া সমস্ত কিছু প্রোগ্রাম ভুলে যায়: সমস্ত ভেরিয়েবল, ফাংশন কল ইত্যাদি এবং allocaস্ট্যাকের ঠিক একটি অ্যারের মতো, সুতরাং এটি আশা করা যায় যে তারা ক্লোবারড হবে স্ট্যাকের সব কিছুর মতো।
tehftw

1
man allocaনিম্নলিখিত বাক্যটি দিয়েছিলেন: "যেহেতু বরাদ্দ () দ্বারা বরাদ্দ করা স্থানটি স্ট্যাক ফ্রেমের মধ্যে বরাদ্দ করা হয়েছে, যদি ফাংশন রিটার্নটি লংজ্যাম্প (3) অথবা সিগলংজ্যাম্প (3) এ কল করে লাফিয়ে যায় তবে স্বয়ংক্রিয়ভাবে স্থানটি মুক্ত হয়" " সুতরাং এটি নথিভুক্ত করা হয় যে মেমরির সাথে বরাদ্দ করা হয় allocaতার পরে ক্লোবার্ব হয়ে যায় longjmp
tehftw

@tehftw অবস্থা বর্ণনা একটি ফাংশন রিটার্ন হচ্ছে উপর jumped ছাড়া ঘটে longjmp। লক্ষ্য ফাংশনটি এখনও ফিরে আসেনি। এটা হয়েছে setjmp, allocaএবং তারপর longjmplongjmpরিওয়াইন্ড করতে পারে allocaতা ছিল রাজ্যের ফিরে setjmpসময়। এর অর্থ, পয়েন্টার দ্বারা সরানো পয়েন্টারটি allocaস্থানীয় ভেরিয়েবলের মতো একই সমস্যায় ভুগছে যা চিহ্নিত করা হয়নি volatile!
কাজ

3
কেন এটি অপ্রত্যাশিত হওয়ার কথা হবে তা আমি বুঝতে পারি না। যখন আপনি setjmpতারপর alloca, এবং তারপর longjmp, এটাই কি স্বাভাবিক যে allocarewinded করা হবে। পুরো বিষয়টি longjmpহ'ল সেই রাজ্যে ফিরে আসা যা সেভ করা হয়েছিল setjmp!
tehftw

@ স্টেটফিউ আমি এই বিশেষ ইন্টারঅ্যাকশনটি নথিভুক্ত কখনও দেখিনি। সুতরাং, এটি সংযোজনকারীদের সাথে অভিজ্ঞতামূলক তদন্ত ব্যতীত অন্য কোনওভাবেই নির্ভর করা যায় না।
কাজ

7

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


7
alloca()বেশী বিপজ্জনক int foo[bar];যেখানে barকিছু অবাধ পূর্ণসংখ্যা।
টড লেহম্যান

@ টাডলিহম্যান এটি সঠিক, এবং ঠিক সেই কারণেই আমরা বেশ কয়েক বছর ধরে কার্নেলে VLAs নিষিদ্ধ করেছি এবং 2018 :-) থেকে VLA- মুক্ত রয়েছি
ক্রিস ডাউন

6

যদি আপনি দুর্ঘটনাক্রমে বরাদ্দকৃত ব্লকের বাইরে alloca(উদাহরণস্বরূপ বাফার ওভারফ্লোর কারণে) লিখে থাকেন তবে আপনি আপনার ফাংশনের রিটার্ন ঠিকানাটি মুছে ফেলবেন , কারণ এটি স্ট্যাকের উপরে "উপরে" অবস্থিত, অর্থাৎ আপনার বরাদ্দকৃত ব্লকের পরে

_লোকা স্ট্যাকের ব্লক

এর পরিণতি দ্বিগুণ:

  1. প্রোগ্রামটি দর্শনীয়ভাবে ক্রাশ হবে এবং কেন বা কোথায় এটি ক্র্যাশ হয়েছে তা বলা অসম্ভব (স্ট্রোকের ওভাররাইটেড পয়েন্টারটির কারণে স্ট্যাকটি সম্ভবত কোনও এলোমেলো ঠিকানায় খুলে যাবে)।

  2. এটি বাফার ওভারফ্লোকে আরও বহুগুণ বিপজ্জনক করে তোলে, যেহেতু দূষিত ব্যবহারকারী একটি বিশেষ পেডলোড খাঁজতে পারে যা স্ট্যাকের উপর চাপানো হয় এবং তাই মৃত্যুদন্ড কার্যকর করতে পারে।

বিপরীতে, আপনি যদি গাদা একটি ব্লকের বাইরে লিখে থাকেন তবে আপনি "স্রেফ" হিপ দুর্নীতি পেতে পারেন। প্রোগ্রামটি সম্ভবত অপ্রত্যাশিতভাবে শেষ হবে তবে স্ট্যাকটি যথাযথভাবে অনাবৃত করবে, ফলে দূষিত কোড কার্যকর করার সম্ভাবনা হ্রাস পাবে।


11
এই পরিস্থিতিতে কোনও কিছুই স্থির আকারের স্ট্যাক-বরাদ্দ বাফারকে উপচে পড়া বিপদের থেকে নাটকীয়ভাবে আলাদা। এই বিপদটি অনন্য নয় alloca
ফোনেটেগার

2
অবশ্যই না. তবে দয়া করে আসল প্রশ্নটি পরীক্ষা করে দেখুন। প্রশ্নটি হল: allocaতুলনায় বিপদটি কী কী malloc(এইভাবে স্ট্যাকের উপর স্থির আকারের বাফার নয়)।
রুস্টিক্স

মাইনর পয়েন্ট, তবে কয়েকটি সিস্টেমে স্ট্যাকগুলি উপরের দিকে বৃদ্ধি পায় (যেমন পিআইসি 16 বিট মাইক্রোপ্রসেসর)।
ইবলাক

5

দুঃখের বিষয় সত্যিকারের দুর্দান্ত alloca()প্রায় সন্ত্রস্ত টিসিসি থেকে অনুপস্থিত। জিসিসি আছে alloca()

  1. এটি তার নিজের ধ্বংসের বীজ বপন করে। ডেস্ট্রাক্টর হিসাবে ফিরে।

  2. malloc()এটির মতো এটি একটি ব্যর্থতার উপরে একটি অবৈধ পয়েন্টার দেয় যা একটি এমএমইউ দিয়ে আধুনিক সিস্টেমে সেগফল্ট করবে (এবং আশা করি এটিগুলি ব্যতীত পুনরায় চালু করা হবে)।

  3. অটো ভেরিয়েবলের বিপরীতে আপনি রান সময়টিতে আকার নির্দিষ্ট করতে পারেন।

এটি পুনরাবৃত্তি সঙ্গে ভাল কাজ করে। লেজ পুনরাবৃত্তির অনুরূপ কিছু অর্জন করতে আপনি স্ট্যাটিক ভেরিয়েবলগুলি ব্যবহার করতে পারেন এবং প্রতিটি পুনরাবৃত্তির জন্য কিছু অন্যান্য পাসের তথ্য ব্যবহার করতে পারেন।

আপনি যদি খুব গভীরভাবে ঠেলাঠেলি করেন তবে আপনাকে সেগফল্টের আশ্বাস দেওয়া হয়েছে (যদি আপনার কোনও এমএমইউ থাকে)।

দ্রষ্টব্য যে malloc()সিস্টেমটি স্মৃতিশক্তি বহির্ভূত হয়ে গেলে NULL ফেরত দেওয়ার কারণে আর কোনও প্রস্তাব নেই (যা নির্ধারিত হলে সেগফল্টও হবে)। অর্থাৎ আপনি যা করতে পারেন তা হ'ল জামিন বা কেবল যে কোনও উপায়ে এটি দেওয়ার চেষ্টা করুন।

ব্যবহার করার জন্য malloc()আমি গ্লোবালগুলি ব্যবহার করি এবং সেগুলি নূন্যতর করি। পয়েন্টারটি যদি নাল না হয় আমি ব্যবহার করার আগেই এটি মুক্ত করি malloc()

realloc()কোনও বিদ্যমান ডেটা অনুলিপি করতে চাইলে আপনি সাধারণ কেস হিসাবেও ব্যবহার করতে পারেন। আপনি যদি অনুলিপিটির পরে অনুলিপি করতে বা কনটেন্টেট করতে চলেছেন তবে কাজ করার আগে আপনাকে পয়েন্টারটি পরীক্ষা করতে হবে realloc()

৩.২.৫.২ বরাদ্দের সুবিধা


4
প্রকৃতপক্ষে বরাদ্দ অনুমানটি এটি ব্যর্থ (স্ট্যাক ওভারফ্লো) এর উপর একটি অবৈধ পয়েন্টার ফেরত দেয় না বলে জানিয়েছে যে এটির পূর্বনির্ধারিত আচরণ রয়েছে ... এবং ম্যালোকের জন্য এটি বলে যে এটি NUL ফেরায়, কোনও এলোমেলো অবৈধ পয়েন্টার নয় (ঠিক আছে, লিনাক্স আশাবাদী মেমরি প্রয়োগ করে তোলে যে বেহুদা)।
ক্রিস

@ ক্রিস লিনাক্স আপনার প্রক্রিয়াটিকে হত্যা করতে পারে, তবে কমপক্ষে এটি
অপরিজ্ঞাত

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

আমি বলার চেষ্টা করছিলাম যে এনএলএল ফিরে আসা ম্যালোক, বা লিনাক্সের ক্ষেত্রে, আপনার প্রক্রিয়াটিকে মেরে ফেলা মেমরির অ্যাক্সেস, বরাদ্দের অপরিজ্ঞাত আচরণের চেয়ে ভাল। আমার মনে হয় আপনার অবশ্যই প্রথম মন্তব্যটি আমার ভুল লেখা উচিত।
ক্রেগ 65535

3

প্রক্রিয়াগুলির মধ্যে কেবলমাত্র সীমিত পরিমাণে স্ট্যাক স্পেস পাওয়া যায় - যা উপলব্ধ মেমরির পরিমাণের চেয়ে অনেক কম malloc()

alloca()আপনি নাটকীয়ভাবে স্ট্যাক ওভারফ্লো ত্রুটি পাওয়ার সম্ভাবনাগুলি নাটকীয়ভাবে বৃদ্ধি করে (যদি আপনি ভাগ্যবান হন, বা যদি না হন তবে একটি অনির্বচনীয় ক্রাশ)।


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

3

খুব সুন্দর নয়, তবে যদি পারফরম্যান্সটি সত্যিই গুরুত্বপূর্ণ হয় তবে আপনি স্ট্যাকের কিছু জায়গা পূর্বনির্ধারিত করতে পারেন।

আপনি যদি ইতিমধ্যে এখন মেমরির সর্বোচ্চ আকারটি আপনার প্রয়োজনটিকে অবরুদ্ধ করেন এবং আপনি ওভারফ্লো চেক রাখতে চান তবে আপনি এমন কিছু করতে পারেন:

void f()
{
    char array_on_stack[ MAX_BYTES_TO_ALLOCATE ];
    SomeType *p = (SomeType *)array;

    (...)
}

12
গৃহস্থালীর অ্যারে কোনও ডেটা টাইপের জন্য সঠিকভাবে সংযুক্ত হওয়ার নিশ্চয়তা দেওয়া আছে কি? বরাদ্দ যেমন প্রতিশ্রুতি দেয়।
জুহো অস্টম্যান

@ জুহোস্টম্যান: আপনার যদি অ্যালগিনমেন্টের সমস্যা থাকে তবে আপনি চরের পরিবর্তে স্ট্রাকের (বা যে কোনও প্রকারের) অ্যারে ব্যবহার করতে পারেন।
ক্রিস

এটিকে একটি চলক দৈর্ঘ্যের অ্যারে বলা হয় । এটি সি 90 এবং এর উপরে সমর্থিত, তবে সি ++ নয়। দেখুন পাবেনা আমি সি ++ 03 এবং সি ++ 11 একটি সি চলক দৈর্ঘ্য এরে ব্যবহার করবেন?
jww

3

বরাদ্দ ফাংশন দুর্দান্ত এবং সমস্ত nayayers কেবল FUD ছড়াচ্ছে।

void foo()
{
    int x = 50000; 
    char array[x];
    char *parray = (char *)alloca(x);
}

অ্যারে এবং পেরে হুবহু একই ধরণের ঝুঁকির সাথে একই। একজনের থেকে অন্যের চেয়ে ভাল বলা একটি সিন্টেক্সিক পছন্দ, কোনও প্রযুক্তিগত নয়।

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

কেন এই খারাপ?


3

আসলে, বরাদ্দ স্ট্যাকটি ব্যবহারের গ্যারান্টিযুক্ত নয়। প্রকৃতপক্ষে, বরাদ্দের gcc-2.95 বাস্তবায়ন নিজেই malloc ব্যবহার করে গাদা থেকে মেমরি বরাদ্দ করে। এছাড়াও বাস্তবায়নটি বাগিচা, এটি আপনি আরও একটি গোটো ব্যবহারের সাথে কোনও ব্লকের ভিতরে কল করলে এটি একটি মেমরি ফাঁস এবং কিছু অপ্রত্যাশিত আচরণের দিকে পরিচালিত করে। না, এটি বলার জন্য যে আপনার কখনই এটি ব্যবহার করা উচিত নয় তবে কিছু সময় বরাদ্দগুলি প্রবাহিত হওয়ার চেয়ে বেশি ওভারহেডের দিকে নিয়ে যায়।


দেখে মনে হচ্ছে জিসিসি-২.৯৯ বরাদ্দ ভেঙেছে এবং সম্ভবত প্রয়োজনীয় প্রোগ্রামগুলির জন্য নিরাপদে ব্যবহার করা যাবে না alloca। যখন longjmpফ্রেমগুলি করা হয়নি তখন এটি কীভাবে স্মৃতি পরিষ্কার করবে alloca? আজ কখন কেউ জিসিসি ব্যবহার করবে?
কাজ

2

আইএমএইচও, বরাদ্দকে খারাপ অভ্যাস হিসাবে বিবেচনা করা হয় কারণ প্রত্যেকে স্ট্যাকের আকার সীমাটি ছাড়িয়ে যাওয়ার ভয় পায়।

আমি এই থ্রেড এবং কিছু অন্যান্য লিঙ্কগুলি পড়ে অনেক কিছু শিখেছি:

আমি মূলত আমার প্লেইন সি ফাইলগুলিকে কোনও পরিবর্তন ছাড়াই এমএসভিসি এবং জিসিসি-তে সংকলনযোগ্য করতে সিএল স্টাইল, কোনও #ifdef _MSC_VER, ইত্যাদি তৈরির জন্য ব্যবহার করি a

ধন্যবাদ ! এই থ্রেডটি আমাকে এই সাইটে সাইন আপ করিয়েছে :)


মনে রাখবেন যে এই সাইটে "থ্রেড" বলে কোনও জিনিস নেই। স্ট্যাক ওভারফ্লোতে একটি প্রশ্নোত্তর ফর্ম্যাট রয়েছে, আলোচনার থ্রেড ফর্ম্যাট নয়। "উত্তর" কোনও আলোচনা ফোরামে "জবাব" দেওয়ার মতো নয়; এর অর্থ আপনি প্রকৃতপক্ষে প্রশ্নের উত্তর সরবরাহ করছেন এবং অন্য উত্তরের জবাব দিতে বা বিষয়টিতে মন্তব্য করতে ব্যবহার করা উচিত নয়। আপনার কমপক্ষে 50 জন প্রতিনিধি থাকলে আপনি মন্তব্য পোস্ট করতে পারেন তবে "কখন আমার মন্তব্য করা উচিত নয় ?" পড়তে ভুলবেন না অধ্যায়. সাইটের ফর্ম্যাটটি সম্পর্কে আরও ভাল ধারণা পেতে দয়া করে পৃষ্ঠাটি পড়ুন ।
আদি ইনবার

1

আমার মতে, বরাদ্দ () যেখানে উপলব্ধ সেখানে কেবলমাত্র বাধা উপায়ে ব্যবহার করা উচিত। অনেকটা "গোটো" এর ব্যবহারের মতো, প্রচুর পরিমাণে যুক্তিযুক্ত লোকের কেবলমাত্র ব্যবহারের ক্ষেত্রেই নয়, বরাদ্দ () এর অস্তিত্বেরও তীব্র বিদ্বেষ রয়েছে।

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

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

স্ট্যাকের উপর ডেটা এবং ফিরতি ঠিকানা / ফ্রেম পয়েন্টার উভয়ই সংরক্ষণ করে এমন আর্কিটেকচারগুলিতে (যা আমি জানি, সেগুলিই সমস্ত), স্ট্যাক বরাদ্দ করা কোনও ভেরিয়েবল বিপজ্জনক হতে পারে কারণ ভেরিয়েবলের ঠিকানা নেওয়া যেতে পারে এবং চেক না করা ইনপুট মানগুলি অনুমতি দিতে পারে সব ধরণের কুফল।

এম্বেড থাকা জায়গাতে বহনযোগ্যতা কোনও উদ্বেগের বিষয় নয়, তবে এটি সাবধানে নিয়ন্ত্রিত পরিস্থিতিতে বাইরে বরাদ্দ () ব্যবহারের বিরুদ্ধে একটি ভাল যুক্তি।

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


1

এখানে বেশিরভাগ উত্তরগুলি মূলত বিন্দুটি মিস করে: ব্যবহার করার কারণ রয়েছে _alloca() কেবল স্ট্যাকের মধ্যে বৃহত বস্তুগুলি সঞ্চয় করার চেয়ে খারাপ worse

স্বয়ংক্রিয় স্টোরেজের মধ্যে প্রধান পার্থক্যটি _alloca()হ'ল পরেরটি অতিরিক্ত (গুরুতর) সমস্যার সাথে ভুগছে: বরাদ্দকৃত ব্লকটি সংকলক দ্বারা নিয়ন্ত্রিত হয় না , তাই সংযোজকটির এটি অপ্টিমাইজ করার বা পুনর্ব্যবহার করার কোনও উপায় নেই।

তুলনা করা:

while (condition) {
    char buffer[0x100]; // Chill.
    /* ... */
}

সঙ্গে:

while (condition) {
    char* buffer = _alloca(0x100); // Bad!
    /* ... */
}

পরবর্তী সমস্যাটি সুস্পষ্ট হওয়া উচিত।


আপনার কি ভিএলএ এবং alloca(হ্যাঁ, আমি ভিএলএ বলছি, কারণ allocaকেবলমাত্র স্ট্যাটিক্যালি আকারের অ্যারেগুলির স্রষ্টার চেয়ে বেশি) পার্থক্য প্রমাণ করে এমন কোনও ব্যবহারিক উদাহরণ রয়েছে ?
রুসলান

দ্বিতীয়টির ক্ষেত্রে ব্যবহারের কেস রয়েছে, যা প্রথম সমর্থন করে না। লুপটি 'এন' বার চালানোর পরে আমি 'এন' রেকর্ড রাখতে চাইব - সম্ভবত কোনও লিঙ্কযুক্ত তালিকা বা গাছের মধ্যে; এই ডেটা স্ট্রাকচারটি তখন ফাংশন অবশেষে ফিরে আসে তখন তা নিষ্পত্তি করা হয়। যা বলার অপেক্ষা রাখে না যে আমি
কোনওভাবেই

1
এবং আমি বলব যে "সংকলক এটি নিয়ন্ত্রণ করতে পারে না" কারণ এ কারণেই বরাদ্দ () নির্ধারিত হয়; আধুনিক সংকলকগণ জানেন যে বরাদ্দ কী, এবং এটি বিশেষভাবে চিকিত্সা করে; এটি কেবল একটি লাইব্রেরি ফাংশন নয় যেমন এটি 80 এর দশকে ছিল। সি 99 ভিএলএগুলি মূলত ব্লক স্কোপ (এবং আরও ভাল টাইপিং) এর সাথে বরাদ্দ। কোনও কম বা কম নিয়ন্ত্রণ নয়, কেবল বিভিন্ন শব্দার্থবিজ্ঞানের সাথে খাপ খাইয়ে নেওয়া।
গ্রেগো

@ গ্রেগগো: আপনি যদি নীচু হয়ে পড়ে থাকেন তবে আমি খুশি হয়ে শুনব কেন আপনি কেন আমার উত্তর কার্যকর না বলে মনে করেন।
অ্যালেকোভ

সি-তে, পুনর্ব্যবহার করা সংকলকের কাজ নয়, পরিবর্তে এটি সি লাইব্রেরির কাজ (ফ্রি ())। বরাদ্দ () রিটার্নে মুক্ত হয়।
পিটারহ - মনিকা

1

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

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

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