উইন্ডোতে __cdecl বা __stdcall?


84

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

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

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

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

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


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

4
__Stdcall কলিং কনভেনশনটি উইন 32 এপিআই ফাংশনগুলিতে কল করতে ব্যবহৃত হয়। ডকস.মাইক্রোসফট.ইন- ইউএস
জান্না

উত্তর:


79

আমি সবেমাত্র কিছু বাস্তব-বিশ্ব টেস্টিং করেছি (ডিএসএল এবং অ্যাপ্লিকেশনগুলি এমএসভিসি ++ এবং মিনজিডাব্লুয়ে সংকলন করুন, তারপরে সেগুলি মিশ্রণ করুন)। এটি প্রদর্শিত হিসাবে, cdeclকলিং সম্মেলনের সাথে আমার আরও ভাল ফলাফল হয়েছিল ।

আরও সুনির্দিষ্টভাবে: সমস্যাটি stdcallহ'ল এমএসভিসি ++ ব্যবহারের পরেও ডিএলএল রফতানি টেবিলের নাম মঙ্গলে extern "C"। উদাহরণস্বরূপ fooহয়ে যায় _foo@4। এটি কেবল তখনই ব্যবহৃত হয় যখন __declspec(dllexport)কোনও ডিএইফ ফাইল ব্যবহার করার সময় নয়; তবে, ডিএএফ ফাইলগুলি আমার মতে রক্ষণাবেক্ষণের ঝামেলা এবং আমি সেগুলি ব্যবহার করতে চাই না।

এমএসভিসি ++ নাম ম্যাংলিংয়ে দুটি সমস্যা রয়েছে:

  • GetProcAddressডিএলএল ব্যবহার করা কিছুটা জটিল হয়ে ওঠে;
  • ডিফল্টরূপে MinGW সজ্জিত নামগুলিতে একটি অনস্ক্রিয়াকে পূর্বে চাপ দেয় না (উদাহরণস্বরূপ MinGW foo@4পরিবর্তে ব্যবহার করবে _foo@4), যা লিঙ্ককে জটিল করে তোলে । এছাড়াও, এটি ডিএলএলগুলির "নন-আন্ডারস্কোর সংস্করণগুলি" দেখার ঝুঁকিটি প্রবর্তন করে এবং অ্যাপ্লিকেশনগুলি "আন্ডারস্কোর সংস্করণগুলি" এর সাথে সামঞ্জস্যপূর্ণ নয় এমন বন্যগুলিতে পপ আপ হয়।

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

এই কারণে, cdeclআমার জন্য একটি স্পষ্ট বিজয়ী।


উল্লেখযোগ্যভাবে, এটি 64৪-বিট ডিএলএল-তে প্রযোজ্য নয়, কারণ __stdcall এবং __cdecl সাধারণত উভয়ই উপেক্ষা করা হয় - তাই রফতানিকারক সি কার্যক্রমে কোনও নাম ম্যাঙ্গালিং হয় না।
jtbr

@jtbr কীভাবে রফতানি করা সি ++ ফাংশন (যেমন না extern "C")?
Ela782

ফাংশন ওভারলোডিং সমর্থন করার জন্য @ ইলা 2 C২ সি ++ এর সর্বদা কিছু নাম ম্যাঙ্গালিং থাকবে। তবে এটি মানসম্মত নয় এবং এভাবে সংকলকগুলির মধ্যে পৃথক হতে পারে।
jtbr

@jtbr দুঃখিত, আমি নাম ম্যাঙ্গালিংয়ের অর্থ বোঝাতে চাই নি। আমি বোঝাতে চাইছিলাম __stdcall এবং __cdecl উভয়ই রফতানিকারক সি ++ ফাংশন সহ 64৪-বিট ডিএলএলগুলিতে খুব উপেক্ষা করা হবে কিনা।
Ela782

4
@ ইলা 782 হ্যাঁ; আমি বিশ্বাস করি যে সমস্ত x86-64 সংকলনে __stdcall এবং __cdecl উপেক্ষা করা হবে। উইকিপিডিয়া দেখুন ।
jtbr

20

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

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

সুতরাং, যদি আপনার সমস্ত ফাংশন স্বাক্ষর স্থিরভাবে সংজ্ঞায়িত হতে চলেছে তবে আমি সম্ভবত সিডিসিএল না হলে স্টাডকালের দিকে ঝুঁকছি।


11

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

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