আরগসি এবং আরজিভি এর ঠিকানাগুলি 12 বাইট পৃথক কেন?


40

আমি আমার কম্পিউটারে নিম্নলিখিত প্রোগ্রামটি চালিয়েছি (-৪-বিট ইন্টেল চলমান লিনাক্স)।

#include <stdio.h>

void test(int argc, char **argv) {
    printf("[test] Argc Pointer: %p\n", &argc);
    printf("[test] Argv Pointer: %p\n", &argv);
}

int main(int argc, char **argv) {
    printf("Argc Pointer: %p\n", &argc);
    printf("Argv Pointer: %p\n", &argv);
    printf("Size of &argc: %lu\n", sizeof (&argc));
    printf("Size of &argv: %lu\n", sizeof (&argv));
    test(argc, argv);
    return 0;
}

প্রোগ্রামের আউটপুট ছিল

$ gcc size.c -o size
$ ./size
Argc Pointer: 0x7fffd7000e4c
Argv Pointer: 0x7fffd7000e40
Size of &argc: 8
Size of &argv: 8
[test] Argc Pointer: 0x7fffd7000e2c
[test] Argv Pointer: 0x7fffd7000e20

পয়েন্টারের আকার &argv8 বাইট। আমি এর ঠিকানা প্রত্যাশিত argcহতে address of (argv) + sizeof (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8কিন্তু তাদের মধ্যে একটি 4 বাইট প্যাডিং হয়। কেন এই ক্ষেত্রে?

আমার ধারণা এটি মেমোরি অ্যালাইনমেন্টের কারণে হতে পারে তবে আমি নিশ্চিত নই।

আমি যে ফাংশনগুলি কল করি তার সাথে একই আচরণ লক্ষ্য করি।


15
কেন না? তারা পৃথক 174 বাইট হতে পারে। একটি উত্তর আপনার অপারেটিং সিস্টেম এবং / অথবা একটি মোড়ক লাইব্রেরির উপর নির্ভর করবে যা সেটআপ করে main
aschepler

2
@ এস্পেল্পার: এটি কোনও র‌্যাপারের উপর নির্ভর করবে না যা সেটআপ করে main। সি তে, mainনিয়মিত ফাংশন হিসাবে ডাকা যেতে পারে, তাই এটি নিয়মিত ফাংশনের মতো আর্গুমেন্ট গ্রহণ করা প্রয়োজন এবং অবশ্যই এবিআইয়ের আনুগত্য করতে হবে।
এরিক পোস্টপিসিল

@ এসচেল্পার: আমি অন্যান্য ক্রিয়াকলাপগুলির জন্যও একই আচরণ লক্ষ্য করি।
লেটমটেক্স

4
এটি একটি আকর্ষণীয় 'চিন্তার পরীক্ষা', তবে সত্যিই, 'আমি কেন ভাবছি' এর চেয়ে বেশি কিছু হওয়া উচিত নয়। এই ঠিকানাগুলি ওএস, সংকলক, সংকলক সংস্করণ, প্রসেসরের আর্কিটেকচারের উপর নির্ভর করে পরিবর্তিত হতে পারে এবং কোনওভাবেই 'রিয়েল লাইফে' নির্ভর করা উচিত নয়।
নীল

উত্তর:


61

আপনার সিস্টেমে প্রথম কয়েকটি পূর্ণসংখ্যা বা পয়েন্টার যুক্তি রেজিস্টারে পাস করা হয় এবং তাদের কোনও ঠিকানা নেই। আপনি যখন তাদের ঠিকানাগুলি সাথে &argcবা এর সাথে &argvনেন, সংকলকটিকে নিবন্ধের লিখিত সামগ্রীগুলি স্থানে স্ট্যাক করার জন্য এবং আপনাকে সেই স্ট্যাকের অবস্থানগুলির ঠিকানা দিয়ে ঠিকানা বানোয়াট করতে হয়। এটি করার ক্ষেত্রে, সংকলকটি এক অর্থে চয়ন করে, স্ট্যাকের যে কোনও জায়গাগুলি এটির পক্ষে সুবিধাজনক হবে।


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

10

আরগসি এবং আরজিভি এর ঠিকানাগুলি 12 বাইট পৃথক কেন?

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

তদুপরি, এমন একটি প্রোগ্রাম নিয়ে আসতে আমার সমস্যা হচ্ছে যাতে কোনও প্রোগ্রামের মধ্যে এই জাতীয় তথ্য কার্যকর হতে পারে। উদাহরণস্বরূপ, এমনকি যদি আপনি "জানেন" যে ঠিকানার ঠিকানার argvআগে 12 বাইট রয়েছে argc, তখনও অন্য পয়েন্টারগুলির মধ্যে একটির অঙ্কের কোনও নির্ধারিত উপায় নেই।


7
@ আর..গিটহাবস্টোফেল্পিংস: একে অপরের থেকে গণনা আংশিকভাবে সংজ্ঞায়িত, ভাল সংজ্ঞায়িত নয়। সি রূপান্তরটি কীভাবে রূপান্তরটি uintptr_tসম্পাদিত হয় তা সম্পর্কে কঠোর নয় এবং এটি অবশ্যই পরামিতিগুলির ঠিকানাগুলির মধ্যে বা আর্গুমেন্টগুলি পাস করার ক্ষেত্রে সম্পর্কের সংজ্ঞা দেয় না।
এরিক পোস্টপিসিল

6
@ আর..গিটহাবস্টোফেল্পিংসিস: আপনি রাউন্ড-ট্রিপ করতে পারবেন এর অর্থ হ'ল g (f (x)) = x, যেখানে x একটি পয়েন্টার, এফ রূপান্তর-পয়েন্টার-এ-ইউআইএনপিটিআর_তে, এবং জি রূপান্তর-uintptr_t-to -pointer। গাণিতিকভাবে এবং যৌক্তিকভাবে, এটি জি (এফ (এক্স) +4) = x + 4 বোঝায় না। উদাহরণস্বরূপ, যদি f (x) x² এবং g (y) স্কয়ার্ট (y) হয়, তবে g (f (x)) = x (আসল অ-নেগেটিভ এক্স এর জন্য), তবে g (f (x) +4) ≠ x + 4, সাধারণভাবে। পয়েন্টারগুলির ক্ষেত্রে, রূপান্তরটি uintptr_tউচ্চ 24 বিটগুলিতে একটি ঠিকানা এবং কম 8 বিটগুলিতে কিছু প্রমাণীকরণ বিট দিতে পারে। তারপরে 4 কেবলমাত্র প্রমাণীকরণের স্ক্রু যুক্ত করুন; এটি আপডেট হয় না…
এরিক পোস্টপিসিল

5
… ঠিকানা বিট। অথবা uintptr_t এ রূপান্তর উচ্চ 16 বিটগুলিতে একটি বেস ঠিকানা এবং কম 16 বিটগুলিতে একটি অফসেট দিতে পারে এবং 4 টি কম বিট যুক্ত করতে উচ্চ বিটগুলিতে বহন করতে পারে তবে স্কেলিংটি ভুল (কারণ প্রতিনিধিত্ব করা ঠিকানাটি নয় বেস • 65536 + অফসেট তবে বেস • 64 + অফসেট, এটি কিছু সিস্টেমে ছিল)। একদম সহজভাবে, uintptr_tআপনি কোনও রূপান্তর থেকে যা পেয়েছেন তা কোনও সহজ ঠিকানা নয় arily
এরিক পোস্টপিসিল

4
আমার মান পড়ার থেকে @ আর..গিটহাবস্টোফেল্পিংস, কেবলমাত্র একটি দুর্বল গ্যারান্টি রয়েছে যা এর সাথে (void *)(uintptr_t)(void *)pতুলনা করবে (void *)p। এবং এটি লক্ষণীয় যে কমিটি প্রায় এই সঠিক বিষয়ে মন্তব্য করেছে এবং এই সিদ্ধান্তে পৌঁছেছে যে "বাস্তবায়ন ... বিভিন্ন উত্সের উপর ভিত্তি করে পয়েন্টারগুলিকে কিছুটা অভিন্ন হলেও তারা পৃথক হিসাবে বিবেচনা করতে পারে ।"
রায়ান অ্যাভেলা

5
@ আর..গিটহাবস্টোফেল্পিংস: দুঃখিত, আমি মিস করেছি যে আপনি uintptr_tপয়েন্টারগুলির চেয়ে আলাদা বা বাইটের "জ্ঞাত" দূরত্বের পরিবর্তে ঠিকানার দুটি রূপান্তরগুলির পৃথক হিসাবে গণনা করে একটি মান যুক্ত করছেন । অবশ্যই, এটি সত্য, তবে এটি কীভাবে কার্যকর? এটি ঠিক রয়ে গেছে যে "উত্তরগুলি যেমন অন্যের থেকে সেই পয়েন্টারগুলির একটি গণনা করার এখনও কোনও নির্ধারিত উপায় নেই" তবে সেই গণনাটি গণনা bথেকে aনয় বরং bউভয় থেকেই গণনা করে aএবং bযেহেতু bপরিমাণ গণনা করতে বিয়োগে অবশ্যই ব্যবহার করতে হবে যোগ করতে. একে অপরের কাছ থেকে গণনা সংজ্ঞায়িত হয় না।
এরিক পোস্টপিসিল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.