আমি বুঝতে পারি একটি স্ট্যাক পয়েন্টার কী - তবে এটি কীসের জন্য ব্যবহৃত হয়?


11

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

তবে স্ট্যাক পয়েন্টারের নির্দেশক কম্পিউটার / প্রোগ্রাম কেন "যত্ন" করে? অন্য কথায়, স্ট্যাক পয়েন্টারটি থাকা এবং এটি কোথায় পরিবেশন করা হয় তা জেনে কী উদ্দেশ্য রয়েছে?

সি প্রোগ্রামারদের দ্বারা বোধগম্য একটি ব্যাখ্যা প্রশংসা করা হবে।


কারণ আপনি রামের মতো স্ট্যাকের শীর্ষটি দেখতে পাচ্ছেন না আপনি থালা থালা থালা দেখতে পারেন।
tkausl


8
আপনি একটি স্ট্যাকের নীচে থেকে একটি থালা গ্রহণ করবেন না । আপনি উপরে একটি যুক্ত করুন এবং অন্য কেউ এটিকে উপরে থেকে নিয়ে যান । আপনি এখানে একটি সারির কথা ভাবছেন।
কিলিয়ান ফট

@ স্বনামান আপনার সম্পাদনা প্রশ্নের অর্থের পরিবর্তন বলে মনে হচ্ছে। মুনম্যান ২৩৯, আপনি কি স্নোম্যানের পরিবর্তন সঠিক কিনা তা যাচাই করতে পারবেন, বিশেষত "এই স্ট্যাকটি এর কাঠামোগুলি ব্যাখ্যা করার বিপরীতে আসলে কী উদ্দেশ্যে কাজ করে?"
বিট্রি

1
@ 8 বিট্রি দয়া করে সম্পাদনা বিবরণটি দেখুন: আমি বিষয়টির লাইনে বর্ণিত প্রশ্নটি প্রশ্নের শিরোনামে অনুলিপি করেছি। অবশ্যই, আমি সর্বদা এই সম্ভাবনার জন্য সর্বদা উন্মুক্ত যে আমি কিছু পরিবর্তন করেছি এবং মূল লেখক সর্বদা পিছনে ফিরে যেতে বা অন্যথায় পোস্ট সম্পাদনা করতে মুক্ত।

উত্তর:


23

এই স্ট্যাকটি এর কাঠামোটি ব্যাখ্যা করার বিপরীতে আসলে কী উদ্দেশ্যে কাজ করে?

আপনার অনেক উত্তর রয়েছে যা স্ট্যাকের মধ্যে সঞ্চিত ডেটার কাঠামোর সঠিকভাবে বর্ণনা করে, যা আমি মনে করি আপনি জিজ্ঞাসা করা প্রশ্নের বিপরীত।

স্ট্যাকটি যে উদ্দেশ্যে কাজ করে তা হ'ল: স্ট্যাকটি কর্টিনগুলি ছাড়াই কোনও ভাষায় ধারাবাহিকতা পুনঃনির্ধারণের অংশ

এটি আনপ্যাক করা যাক।

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

রেফারেন্সটি একটি বিমূর্ত ধারণার একটি দৃ concrete় প্রয়োগের জন্য একটি হাইফালিউটিন শব্দ মাত্র। "এরপরে কি হবে?" একটি বিমূর্ত ধারণা; স্ট্যাকটি যেভাবে স্থাপন করা হয়েছে তা হ'ল বিমূর্ত ধারণাটি কীভাবে একটি বাস্তব মেশিনে রূপান্তরিত হয় যা সত্যই জিনিসগুলিকে গণনা করে।

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

কিভাবে একটি স্ট্যাক ধারাবাহিকতা বাস্তবায়ন করে? অন্যান্য উত্তরগুলি কীভাবে বলে। স্ট্যাক (1) ভেরিয়েবল এবং টেম্পোরারিগুলির মানগুলি যার লাইফটাইম বর্তমান পদ্ধতির সক্রিয়করণের চেয়ে বেশি নয় বলে পরিচিত এবং (2) সাম্প্রতিকতম পদ্ধতি সক্রিয়করণের সাথে সম্পর্কিত ধারাবাহিকতা কোডের ঠিকানা। ব্যতিক্রমী ভাষায় স্ট্যাক পরিচালনা করে এমন ভাষাগুলিতে "ত্রুটির ধারাবাহিকতা" সম্পর্কেও তথ্য সংরক্ষণ করা যেতে পারে - অর্থাত্ ব্যতিক্রমী পরিস্থিতি দেখা দিলে প্রোগ্রামটি পরবর্তী সময়ে কী করবে।

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

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


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

2
আমি বেশ নির্দিষ্ট একটি ব্যাখ্যা স্পষ্টতা বাড়াতে হবে বলে মনে হয় । আমি সম্পূর্ণরূপে নিশ্চিত নই যে "" স্ট্যাকটি কোনও কর্টিন ছাড়া ভাষায় ধারাবাহিকতা পুনঃনির্ধারণের অংশ "এটি আরও কাছাকাছি আসে :-)

4

স্ট্যাকের সর্বাধিক প্রাথমিক ব্যবহার হ'ল ফাংশনগুলির জন্য রিটার্ন ঠিকানা সঞ্চয় করা:

void a(){
    sub();
}
void b(){
    sub();
}
void sub() {
    //should i got back to a() or to b()?
}

এবং সি দৃষ্টিকোণ থেকে এই সব। সংকলক দৃষ্টিকোণ থেকে:

  • সমস্ত ফাংশন আর্গুমেন্ট সিপিইউ রেজিস্ট্রার দ্বারা পাস করা হয় - পর্যাপ্ত রেজিস্টার না থাকলে আর্গুমেন্ট স্ট্যাক করা হবে
  • ফাংশন শেষ হওয়ার পরে (সর্বাধিক) রেজিস্টারগুলিতে প্রবেশের পূর্বে একই মান থাকতে হবে - সুতরাং ব্যবহৃত রেজিস্টারগুলিকে স্ট্যাকের সাহায্যে ব্যাক আপ করা হয়

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

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


1
আমি মনে করি এটি যুক্তিযুক্ত হওয়া আরও সঠিক যে যুক্তিগুলি স্ট্যাকের দিকে ঠেলাঠেলি করা হয়, যদিও প্রায়শই প্রসেসরের পরিবর্তে অপ্টিমাইজেশন রেজিস্টারগুলি ব্যবহার করা হয় যার পক্ষে টাস্কের জন্য পর্যাপ্ত ফ্রি রেজিস্টার রয়েছে isters এটি একটি নিট, তবে আমি মনে করি ভাষাগুলি কীভাবে historতিহাসিকভাবে বিকশিত হয়েছে এটি আরও ভাল মেলে। প্রারম্ভিক সি / সি ++ সংকলকরা এর জন্য নিবন্ধগুলি মোটেই ব্যবহার করেনি।
রোবট

4

লিফো বনাম ফিফো

লিফো মানে লাস্ট ইন, ফার্স্ট আউট। হিসাবে, স্ট্যাকের মধ্যে রাখা সর্বশেষ আইটেমটি স্ট্যাকের বাইরে নেওয়া প্রথম আইটেম।

আপনি আপনার থালা খাবার উপমা ( প্রথম সংশোধনীতে ) দিয়ে যা বর্ণনা করেছেন তা হ'ল একটি সারি বা ফিফো, ফার্স্ট ইন, ফার্স্ট আউট।

উভয়ের মধ্যে প্রধান পার্থক্য হ'ল লিফো / স্ট্যাক একই প্রান্ত থেকে পুশ (সন্নিবেশ) এবং পপস (অপসারণ), এবং একটি ফিফো / সারি বিপরীত প্রান্ত থেকে তাই করে।

// Both:

Push(a)
-> [a]
Push(b)
-> [a, b]
Push(c)
-> [a, b, c]

// Stack            // Queue
Pop()               Pop()
-> [a, b]           -> [b, c]

স্ট্যাক পয়েন্টার

স্ট্যাকের আড়ালে কী ঘটছে তা একবার দেখে নিই under এখানে কিছু স্মৃতি রয়েছে, প্রতিটি বাক্সের একটি ঠিকানা:

...[ ][ ][ ][ ]...                       char* sp;
    ^- Stack Pointer (SP)

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

সুতরাং আসুন a, b, and cআবার ধাক্কা । বামদিকে গ্রাফিকস, মাঝখানে "উচ্চ স্তরের" অপারেশন, ডানদিকে সি-ইশ সিউডো কোড:

...[a][ ][ ][ ]...        Push('a')      *sp = 'a';
    ^- SP
...[a][ ][ ][ ]...                       ++sp;
       ^- SP

...[a][b][ ][ ]...        Push('b')      *sp = 'b';
       ^- SP
...[a][b][ ][ ]...                       ++sp;
          ^- SP

...[a][b][c][ ]...        Push('c')      *sp = 'c';
          ^- SP
...[a][b][c][ ]...                       ++sp;
             ^- SP

আপনি দেখতে পাচ্ছেন, প্রতিবার আমরা push, এটি স্ট্যাক পয়েন্টারটি বর্তমানে নির্দেশ করছে এমন স্থানে যুক্তি সন্নিবেশ করিয়ে দেয় এবং স্ট্যাক পয়েন্টারটিকে পরবর্তী অবস্থানে নির্দেশ করতে সামঞ্জস্য করে।

এখন পপ করা যাক:

...[a][b][c][ ]...        Pop()          --sp;
          ^- SP
...[a][b][c][ ]...                       return *sp; // returns 'c'
          ^- SP
...[a][b][c][ ]...        Pop()          --sp;
       ^- SP
...[a][b][c][ ]...                       return *sp; // returns 'b'
       ^- SP

Popএর বিপরীত push, এটি স্ট্যাক পয়েন্টারটিকে পূর্ববর্তী স্থানে নির্দেশ করতে সামঞ্জস্য করে এবং সেখানে উপস্থিত আইটেমটি সরিয়ে দেয় (সাধারণত যাকে ডাকে তাকে ফিরিয়ে দিতে pop)।

আপনি সম্ভবত এটি লক্ষ্য করেছেন bএবং cএখনও স্মৃতিতে রয়েছেন। আমি কেবল আপনাকে নিশ্চিত করতে চাই যে সেগুলি টাইপস নয়। আমরা শীঘ্রই এটি ফিরে যাব।

স্ট্যাক পয়েন্টার ছাড়াই জীবন

আসুন দেখুন আমাদের স্ট্যাক পয়েন্টার না থাকলে কী হয়। আবার ঠেলাঠেলি দিয়ে শুরু:

...[ ][ ][ ][ ]...
...[ ][ ][ ][ ]...        Push(a)        ? = 'a';

এর, হুম ... আমাদের যদি স্ট্যাক পয়েন্টার না থাকে তবে আমরা যে ঠিকানার দিকে ইঙ্গিত করে তাতে কিছু স্থানান্তরিত করতে পারি না। হতে পারে আমরা একটি পয়েন্টার ব্যবহার করতে পারি যা শীর্ষের পরিবর্তে বেসকে নির্দেশ করে।

...[ ][ ][ ][ ]...                       char* bp; // "base pointer"
    ^- bp                                bp = malloc(...);

...[a][ ][ ][ ]...        Push(a)        *bp = 'a';
    ^- bp
// No stack pointer, so no need to update it.
...[b][ ][ ][ ]...        Push(b)        *bp = 'b';
    ^- bp

আহ ওহ. যেহেতু আমরা স্ট্যাকের বেসের স্থির মানটি পরিবর্তন করতে পারি না, আমরা কেবল একই স্থানে aচাপ bদিয়ে ওভাররোট করি ।

ঠিক আছে, আমরা কতবার ঠেলেছি তার খোঁজ কেন রাখি না। এবং আমাদের পপ করার সময়গুলিও আমাদের লক্ষ্য রাখতে হবে।

...[ ][ ][ ][ ]...                       char* bp; // "base pointer"
    ^- bp                                bp = malloc(...);
                                         int count = 0;

...[a][ ][ ][ ]...        Push(a)        bp[count] = 'a';
    ^- bp
...[a][ ][ ][ ]...                       ++count;
    ^- bp
...[a][b][ ][ ]...        Push(a)        bp[count] = 'b';
    ^- bp
...[a][b][ ][ ]...                       ++count;
    ^- bp
...[a][b][ ][ ]...        Pop()          --count;
    ^- bp
...[a][b][ ][ ]...                       return bp[count]; //returns b
    ^- bp

ভাল এটি কাজ করে, তবে এটি আসলে আগের মতো বেশ সমান, ব্যয় করার *pointerচেয়ে কম pointer[offset](অতিরিক্ত গাণিতিক নয়) ব্যতীত এটি উল্লেখ না করা। এটাই আমার ক্ষতি বলে মনে হচ্ছে।

আবার চেষ্টা করা যাক. অ্যারে-ভিত্তিক সংকলনের (সংগ্রহের মধ্যে কতগুলি আইটেম রয়েছে তা ট্র্যাকিং) সন্ধানের জন্য পাস্কাল স্ট্রিং স্টাইলটি ব্যবহার না করে, আসুন সি স্ট্রিং স্টাইলটি চেষ্টা করুন (শুরু থেকে শেষ পর্যন্ত স্ক্যান করুন):

...[ ][ ][ ][ ]...                       char* bp; // "base pointer"
    ^- bp                                bp = malloc(...);

...[ ][ ][ ][ ]...        Push(a)        char* top = bp;
    ^- bp, top
                                         while(*top != 0) { ++top; }
...[ ][ ][ ][a]...                       *top = 'a';
    ^- bp    ^- top

...[ ][ ][ ][ ]...        Pop()          char* top = bp;
    ^- bp, top
                                         while(*top != 0) { ++top; }
...[ ][ ][ ][a]...                       --top;
    ^- bp       ^- top                   return *top; // returns '('

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

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

তার উপরে, আমরা ও (1) অপারেশনগুলি ও (এন) অপারেশনে পরিবর্তন করেছি changed

টি এল; ডিআর

স্ট্যাক পয়েন্টার স্ট্যাকের শীর্ষের উপর নজর রাখে, যেখানে সমস্ত ক্রিয়া ঘটে। এটিকে পরিত্রাণের বিভিন্ন উপায় রয়েছে ( bp[count]এবং topমূলত স্ট্যাক পয়েন্টার এখনও রয়েছে), তবে তারা উভয়ই কেবল স্ট্যাক পয়েন্টার না রেখে আরও জটিল এবং ধীর হয়ে যায়। এবং স্ট্যাকের শীর্ষটি কোথায় তা না জানা মানে আপনি স্ট্যাকটি ব্যবহার করতে পারবেন না।

দ্রষ্টব্য: x86 এ রানটাইম স্ট্যাকের "নীচে" দিকে ইঙ্গিত করা স্ট্যাক পয়েন্টারটি পুরো রানটাইম স্ট্যাকটি উল্টে থাকার সাথে সম্পর্কিত একটি ভুল ধারণা হতে পারে। অন্য কথায়, স্ট্যাকের ভিত্তি একটি উচ্চ মেমরির ঠিকানায় স্থাপন করা হয় এবং স্ট্যাকের ডগাটি নীচের স্মৃতি ঠিকানাগুলিতে বৃদ্ধি পায় grows স্ট্যাক পয়েন্টার আছে স্ট্যাকের যেখানে সব কর্ম ঘটে, ঠিক যে ডগা স্ট্যাক বেস কম মেমরি অ্যাড্রেস এ ডগা বিন্দু।


2

কল স্ট্যাকের জন্য স্ট্যাক পয়েন্টারটি (ফ্রেম পয়েন্টার সহ) ব্যবহৃত হয় ( উইকিপিডিয়াতে লিঙ্কটি অনুসরণ করুন, যেখানে একটি ভাল ছবি রয়েছে)।

কল স্ট্যাক কল ফ্রেম, যা ফিরতি ঠিকানা, স্থানীয় ভেরিয়েবল এবং অন্যান্য স্থানীয় ডেটা ধারণ (বিশেষ করে রয়েছে চিত্তভ্রংশ ; formals রেজিস্টার বিষয়বস্তুর)।

সম্পর্কে আরো পড়ুন লেজ কল (কিছু লেজ-recursive কল কোনো কল ফ্রেম প্রয়োজন হবে না), ব্যতিক্রম হ্যান্ডলিং (যেমন setjmp & longjmp , তারা একবারে অনেকগুলি স্ট্যাকের ফ্রেম পপিং যুক্ত থাকতে পারে), সংকেতবিঘ্নিত , এবং continuations । আরও দেখুন কলিং নিয়মাবলী এবং আবেদন বাইনারি ইন্টারফেসগুলি (Abis), বিশেষ করে x86-64 'ABI- র (যা সংজ্ঞায়িত যে কিছু আনুষ্ঠানিক আর্গুমেন্ট রেজিস্টার দ্বারা গৃহীত হয়)।

এছাড়াও, সিতে কিছু সাধারণ ফাংশন (গুলি) কোড করুন, তারপরে gcc -Wall -O -S -fverbose-asm এটি সংকলন করতে ব্যবহার করুন এবং উত্পন্ন .s এসেমব্লার ফাইলটি দেখুন।

আপেল একটি পুরাতন 1986 এর কাগজ লিখেছিল যে জঞ্জাল সংগ্রহগুলি স্ট্যাক বরাদ্দের চেয়ে দ্রুততর হতে পারে ( সংকলকটিতে ধারাবাহিকতা-পাসিং স্টাইল ব্যবহার করে ) তবে এটি সম্ভবত আজকের x86 প্রসেসরের (বিশেষত ক্যাশে প্রভাবের কারণে) মিথ্যা।

লক্ষ্য করুন যে কলিং কনভেনশন, এবিআই এবং স্ট্যাক লেআউট 32 বিট আই 686 এবং 64 বিট x86-64 এ আলাদা। এছাড়াও, কলিং কনভেনশনগুলি (এবং কল ফ্রেম বরাদ্দকরণ বা পপ করার জন্য কে দায়বদ্ধ) বিভিন্ন ভাষার সাথে আলাদা হতে পারে (যেমন সি, পাস্কাল, ওকামল, এসবিসিএল কমন লিস্পের বিভিন্ন কলিং কনভেনশন রয়েছে ....)

বিটিডাব্লু, এভিএক্সের মতো সাম্প্রতিক x86 এক্সটেনশনগুলি স্ট্যাক পয়েন্টারটিতে ক্রমবর্ধমান বৃহত সারিবদ্ধতা সীমাবদ্ধ করছে (আইআইআরসি, x86-64-তে একটি কল ফ্রেম 16 বাইট, অর্থাৎ দুটি শব্দ বা পয়েন্টার সাথে সারিবদ্ধ হতে চায়)।


1
আপনি উল্লেখ করতে চাইতে পারেন যে x86-64 এ 16 বাইট প্রান্তিককরণের অর্থ পয়েন্টারের আকার / প্রান্তিককরণের দ্বিগুণ, যা আসলে বাইট-কাউন্টের চেয়ে আকর্ষণীয়।
উত্সাহীকারী

1

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

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

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


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

@ এরিকলিপার্ট: "পুরোপুরি বুদ্ধিমান" এর মানগুলির পক্ষে যথেষ্ট বোকামি যে তাদের মাথার উপরে দাঁড়ানো এবং নিজেকে ভেতরে ঘুরিয়ে দেওয়া সম্ভবত রয়েছে। ;-)
ম্যাসন হুইলারের

1
ধারাবাহিকতা অতিক্রম করার সাথে সাথে কোনও কল স্ট্যাকের প্রয়োজন হয় না তা সম্ভব। কার্যকরভাবে, প্রতিটি কলটি ফিরার চেয়ে একটি লেজ কল এবং গোটো। "সিপিএস এবং টিসিও যেমন একটি অন্তর্নিহিত ফাংশন রিটার্নের ধারণাটি বাদ দেয়, তাদের সম্মিলিত ব্যবহার রান-টাইম স্ট্যাকের প্রয়োজনীয়তা দূর করতে পারে।"

@ মিশেলটি: আমি বলেছিলাম "মূলত" কোনও কারণে অসম্ভব। সিপিএস তাত্ত্বিকভাবে এটি সম্পাদন করতে পারে, তবে বাস্তবে সিরিজের ব্লগ পোস্টগুলিতে সিরিজের ইঙ্গিত করার কারণে , সিপিএসে যে কোনও জটিলতার বাস্তব-বিশ্ব কোড লিখতে খুব দ্রুত হাস্যকর কাজ হয়ে যায় ।
ম্যাসন হুইলারের

1
@ মেসনওহিলার এরিক সিপিএসে সংকলিত প্রোগ্রামগুলি সম্পর্কে কথা বলছেন । উদাহরণস্বরূপ, জন হ্যারোপের ব্লগের উদ্ধৃতি : In fact, some compilers don’t even use stack frames [...], and other compilers like SML/NJ convert every call into continuation style and put stack frames on the heap, splitting every segment of code between a pair of function calls in the source into its own separate function in the compiled form.এটি "[স্ট্যাক] এর নিজস্ব সংস্করণ প্রয়োগ করা" থেকে পৃথক।
ডোভাল

1

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

স্ট্যাক পয়েন্টারটি চেইনের সর্বনিম্ন লিঙ্ককে বোঝায় এবং প্রসেসর দ্বারা "দেখার" জন্য এটি ব্যবহৃত হয় যেখানে সর্বনিম্ন লিঙ্কটি থাকে, যাতে লিঙ্কগুলি সিলিং থেকে নীচে পুরো চেইন ভ্রমণ না করে যুক্ত করা বা সরিয়ে ফেলা যায়।

এক অর্থে, x86 প্রসেসরের অভ্যন্তরে, স্ট্যাকটি একেবারে নীচে থাকলেও সাধারণ স্ট্যাক-টার্মিনোলজিক্যাল সিলে ব্যবহৃত হয়, যাতে সর্বনিম্ন লিঙ্কটি শীর্ষ হিসাবে চিহ্নিত হয় স্ট্যাকের ।


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


1
The stack pointer refers to the lowest link of the chain and is used by the processor to "see" where that lowest link is, so that links can be added or removed without having to travel the entire chain from the ceiling down.আমি নিশ্চিত নই যে এটি একটি ভাল উপমা। বাস্তবে লিঙ্কগুলি কখনই যুক্ত বা সরানো হয় না। স্ট্যাক পয়েন্টারটি আপনি লিঙ্কগুলির একটিতে চিহ্নিত করার জন্য ব্যবহার করেন এমন কিছু টেপের মতো। আপনি যদি সেই টেপটি হারিয়ে ফেলেন, তবে আপনি জানার উপায় নেই যে আপনি নীচে সবচেয়ে নীচের লিঙ্কটি ব্যবহার করেছিলেন ; নীচে সিলিং থেকে চেইন ভ্রমণ আপনাকে সাহায্য করবে না।
ডোভাল

সুতরাং স্ট্যাক পয়েন্টার একটি রেফারেন্স পয়েন্ট সরবরাহ করে যে প্রোগ্রাম / কম্পিউটার কোনও ফাংশনের স্থানীয় ভেরিয়েবলগুলি খুঁজতে ব্যবহার করতে পারে?
moonman239

যদি তা হয় তবে কম্পিউটার কীভাবে স্থানীয় ভেরিয়েবলগুলি খুঁজে পাবে? এটি কি নীচে থেকে প্রতিটি মেমরি ঠিকানা সন্ধান করতে চলেছে?
moonman239

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

1
পুনঃটুইট আপনি কোথাও মাঝখানে বাইরে থাকাকালীন পছন্দ করুন এবং আপনাকে সহায়তা প্রয়োজন, সুতরাং আপনি 911 কে আপনি ল্যান্ডমার্কের সাথে তুলনামূলকভাবে ধারণা দেবেন। এই ক্ষেত্রে, স্ট্যাক পয়েন্টারটি সাধারণত নিকটতম "ল্যান্ডমার্ক" এবং তাই, সম্ভবত সর্বোত্তম রেফারেন্স পয়েন্ট।
moonman239

1

এই উত্তরটি ইঙ্গিত করে স্ট্যাক পয়েন্টার বর্তমান থ্রেড (মৃত্যুদণ্ড) এর

পদ্ধতিগত প্রোগ্রামিং ভাষায়, একটি থ্রেড সাধারণত স্ট্যাক 1 এ অ্যাক্সেস করে নিম্নলিখিত উদ্দেশ্যে :

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

দ্রষ্টব্য 1 : থ্রেডের ব্যবহারের জন্য উত্সর্গীকৃত, যদিও এর বিষয়বস্তু সম্পূর্ণরূপে পঠনযোগ্য - এবং স্ম্যাশযোগ্য - অন্যান্য থ্রেড দ্বারা।

সমাবেশ প্রোগ্রামিং, সি, এবং সি ++ এ তিনটি উদ্দেশ্য একই স্ট্যাকের দ্বারা পূরণ করা যেতে পারে। অন্য কয়েকটি ভাষায়, কিছু উদ্দেশ্য পৃথক স্ট্যাক বা গতিশীলভাবে বরাদ্দ মেমরির দ্বারা পূরণ করা যেতে পারে।


1

স্ট্যাকটি কীসের জন্য ব্যবহার করা হয়েছে তার একটি ইচ্ছাকৃতভাবে ওভারসিম্প্লিফাইড সংস্করণ এখানে।

সূচক কার্ডগুলির গাদা হিসাবে স্ট্যাকটি কল্পনা করুন। স্ট্যাক পয়েন্টার শীর্ষ কার্ডের দিকে নির্দেশ করে।

যখন আপনি কোনও ফাংশন কল করবেন:

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

এই মুহুর্তে, ফাংশনটিতে কোডটি চলমান। কোডটি প্রতিটি কার্ড শীর্ষের সাথে সম্পর্কিত কিনা তা জানতে সংকলিত। সুতরাং এটি জানে যে ভেরিয়েবল xশীর্ষ থেকে তৃতীয় কার্ড (যেমন স্ট্যাক পয়েন্টার - 3) এবং এটি প্যারামিটারy শীর্ষ থেকে ষষ্ঠ কার্ড (যেমন স্ট্যাক পয়েন্টার - 6) 6.

এই পদ্ধতির মানে হল যে প্রতিটি স্থানীয় ভেরিয়েবল বা পরামিতির ঠিকানা কোডে বেক করা প্রয়োজন হয় না। পরিবর্তে, এই সমস্ত ডেটা আইটেমগুলি স্ট্যাক পয়েন্টারের তুলনায় সম্বোধন করা হয়।

যখন ফাংশনটি ফিরে আসে, বিপরীত অপারেশনটি কেবল:

  • চিহ্নিতকারী কার্ড সন্ধান করুন এবং এর উপরে সমস্ত কার্ড ফেলে দিন throw (যেমন, সংরক্ষিত ঠিকানায় স্ট্যাক পয়েন্টার সেট করুন))
  • আগে সংরক্ষণ করা কার্ডগুলি থেকে নিবন্ধগুলি পুনরুদ্ধার করুন এবং তাদের ফেলে দিন। (যেমন স্ট্যাক পয়েন্টার থেকে একটি নির্দিষ্ট মান বিয়োগ)
  • উপরে কার্ডের ঠিকানা থেকে কোড চালনা শুরু করুন এবং তারপরে এটি ফেলে দিন। (যেমন স্ট্যাক পয়েন্টার থেকে 1 বিয়োগ করুন।)

স্ট্যাকটি ডাকার আগে এই স্ট্যাকটি এখন আবার ফিরে এসেছে called

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

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


1

আধুনিক প্রোগ্রামিং ল্যাঙ্গুয়েজগুলি যেমন আপনি ভাল জানেন, সাব্রোটিন কলগুলির ধারণাকে সমর্থন করে (প্রায়শই "ফাংশন কল" নামে পরিচিত)। এই যে মানে:

  1. কিছু কোডের মাঝামাঝি, আপনি আপনার প্রোগ্রামে অন্য কোনও ফাংশন কল করতে পারেন ;
  2. এই ফাংশনটি স্পষ্ট করে জানতে পারে না যে কোথা থেকে বলা হয়েছিল;
  3. তবুও, যখন এটির কাজ শেষ returnহয়ে যায় এবং এটি হয় , সমস্ত স্থানীয় ভেরিয়েবল মান কার্যকরভাবে কলটি শুরু হওয়ার সাথে সাথে কার্যকরভাবে কলটি শুরু হয়েছিল সেখানে নিয়ন্ত্রণটি ফিরে যায়।

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

এবং যেহেতু এই কল / রিটার্ন প্যাটার্নটি অতীব গুরুত্বপূর্ণ তাই সিপিইউগুলি এর জন্য বিশেষ হার্ডওয়্যার সমর্থন সরবরাহ করার জন্য দীর্ঘকাল পরিকল্পিত। স্ট্যাক পয়েন্টার হ'ল সিপিইউ-তে একটি হার্ডওয়্যার বৈশিষ্ট্য register একটি রেজিস্টার যা স্ট্যাকের শীর্ষের উপর নজর রাখতে কেবল উত্সর্গীকৃত, এবং সিপিইউর নির্দেশকে সাব্রোটিনে শাখা করা এবং এটি থেকে ফিরে আসার জন্য ব্যবহৃত হয়।

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