পয়েন্টার আর্গুমেন্টের সাহায্যে কোনও সি ++ পদ্ধতি কোনও সি ফাংশনে রূপান্তর করা কি গ্রহণযোগ্য প্যাটার্ন?


16

আমি ESP-32 এ সি ++ ব্যবহার করি। টাইমার নিবন্ধনের সময় আমাকে এটি করতে হবে:

timer_args.callback = reinterpret_cast<esp_timer_cb_t>(&SoundMixer::soundCallback);
timer_args.arg = this;

এখানে টাইমার কল soundCallback

কোনও কাজ নিবন্ধনের সময় একই জিনিস:

xTaskCreate(reinterpret_cast<TaskFunction_t>(&SoundProviderTask::taskProviderCode), "SProvTask", stackSize, this, 10, &taskHandle);

সুতরাং পদ্ধতিটি একটি পৃথক টাস্কে শুরু করা হয়েছে।

জিসিসি আমাকে সর্বদা এই রূপান্তরগুলি সম্পর্কে সতর্ক করে, তবে এটি পরিকল্পনা মতো কাজ করে।

এটি কি উত্পাদন কোডে গ্রহণযোগ্য? এই কাজ করতে একটি ভাল উপায় আছে কি?

উত্তর:


47

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

স্বাভাবিক পদ্ধতির পরিবর্তে উপযুক্ত স্বাক্ষরের সাথে একটি সি-সামঞ্জস্যপূর্ণ ফাংশনটি সংজ্ঞায়িত করা হবে, যা অভ্যন্তরীণভাবে সি ++ পদ্ধতিটিকে কল করে। উদাহরণ স্বরূপ:

extern "C" static void my_timer_callback(void* arg) {
  static_cast<SoundMixer*>(arg)->soundCallback();
}

এই castালাই ঠিক আছে কারণ আমরা একটি void*থেকে পয়েন্ট-টু অবজেক্টের ধরণে cast ালছি।

বিবরণ:

  • extern "C"এই ফাংশনটির ভাষা লিঙ্কেজ নির্দিষ্ট করে । ভাষার লিঙ্কেজ নাম মাংলিং এবং ফাংশনের কলিং কনভেনশনকে প্রভাবিত করে। সদস্য ফাংশনগুলিতে সি ভাষার সংযোগ থাকতে পারে না। ভাষার সংযোগটি মূলত অভ্যন্তরীণ / বাহ্যিক সংযোগের জন্য orthogonal।

  • কলব্যাকের জন্য ফাংশনটি "ব্যক্তিগত" হতে পারে, অর্থাত্ অভ্যন্তরীণ সংযোগ থাকতে পারে। সি কোড কখনই নাম দিয়ে কলব্যাক বোঝায় না। উপরের কোড স্নিপেট staticকীওয়ার্ডের মাধ্যমে অভ্যন্তরীণ সংযোগ নির্দিষ্ট করে (কোনও স্থির পদ্ধতি নয়!)। বিকল্পভাবে, ফাংশনটি একটি বেনাম নামস্থানে স্থাপন করা যেতে পারে।

    আমি ( extern "C"এবং staticঅভ্যন্তরীণ লিঙ্কেজ) এর মধ্যে মিথস্ক্রিয়া সম্পর্কে পুরোপুরি নিশ্চিত নই । যেমন [dcl.link]বলছেন যে "সমস্ত ফাংশন ধরনের, বহিরাগত দুটো ঘটনার সঙ্গে ফাংশন নাম, এবং বহিরাগত দুটো ঘটনার সঙ্গে পরিবর্তনশীল নামের একটি ভাষা দুটো ঘটনার আছে।" আমি এই যাতে ব্যাখ্যা করা টাইপ এর my_timer_callbackসি ল্যাঙ্গুয়েজ দুটো ঘটনার আছে, কিন্তু তার ফাংশন যা নাম না।

  • static_castএখানে উপযুক্ত কারণ আমরা প্রকৃত প্রকারটি জানি argতবে এটি টাইপ সিস্টেমের মধ্যে প্রকাশ করতে পারি না। বিপরীতে একটি reinterpret_castউপযুক্ত যখন আমরা একটি বিট প্যাটার্নটির পুনরায় ব্যাখ্যা করতে চাই, যেমন একটি সংখ্যার ধরণের পয়েন্টার a

  • ফাংশনগুলি কোনও সাধারণ অবজেক্ট নয় এবং সদস্যের ফাংশনগুলিও এর চেয়ে কম হয়। ফাংশনটি কেবলমাত্র তার আসল প্রকারের মাধ্যমে (এবং সদস্য ফাংশন পয়েন্টারগুলির জন্য অ্যানালগালি) দ্বারা ফাংশন পয়েন্টার প্রকারের মধ্যে পুনরায় ব্যাখ্যা-কাস্ট করতে পারেন। আপনি অন্য ধরণের ফাংশন পয়েন্টার কাস্ট করতে পারেন (যেমন বস্তু পয়েন্টার বা শূন্য পয়েন্টার) বাস্তবায়ন-সংজ্ঞায়িত ( ব্যাকগ্রাউন্ড )। POSIX এ ফাংশন পয়েন্টারগুলির মধ্যে কাস্ট হয় এবং void*অনুমতি দেওয়া হয় যাতে এটি dlsym()কাজ করতে পারে। (সদস্য) ফাংশন পয়েন্টার জড়িত অন্যান্য কাস্টগুলি অপরিজ্ঞাত। বিশেষত, সদস্য ফাংশন এবং ফাংশন পয়েন্টারগুলির মধ্যে কাস্টগুলি সম্ভব নয়।


1
std::bindপ্রথম পদ্ধতির আর্গুমেন্ট হিসাবে অবজেক্ট পয়েন্টারটিকেও ধরে না ?
বলেছেন মনিকা পুনরায় ইনস্টল করুন

5
@ ওয়াল হ্যাঁ, তবে এর অর্থ এই নয় যে সদস্য ফাংশনগুলি সাধারণ ফাংশনগুলির সাথে সামঞ্জস্যপূর্ণ, কেবলমাত্র এই বাঁধাই () ইনভোক এলগরিদম ব্যবহার করে যা সদস্য ফাংশনগুলিকে সাধারণ ফাংশন অবজেক্টগুলি থেকে পৃথক কেস হিসাবে পরিচালনা করে। ফাংশন পয়েন্টার। কারণ স্ট্যান্ড :: বাইন্ড () একটি ফান্টর তৈরি করে এটি সি এর সাথে ইন্টারফেস করার পক্ষে উপযুক্ত নয়
amon

1
আরেকটি প্রশ্ন: আমার extern "C"এখানে কেন দরকার ? এই ক্ষেত্রে সি লিঙ্কেজ কি গুরুত্বপূর্ণ?
বলেছেন মনিকা পুনরায় ইনস্টল করুন

5
@ ওভাল আপনি যদি সি থেকে সেই ফাংশনটি কল করতে সক্ষম হতে চান তবে এটি অবশ্যই সি কলিং কনভেনশনটি ব্যবহার করবে। এটি সি ভাষা সংযোগের সাথে ফাংশনটি ঘোষণা করে বা সংকলক-নির্দিষ্ট এক্সটেনশনগুলির দ্বারা (যেমন __attribute__((cdecl)), তবে দয়া করে এটি করবেন না) দ্বারা করা যেতে পারে। সি ++ ফাংশনটি অন্যথায় সি-সামঞ্জস্যপূর্ণ কলিং কনভেনশন করার গ্যারান্টিযুক্ত নয় (যদিও জিসিসিতে এটি সাধারণত সূক্ষ্মভাবে কাজ করে)।
আমন

4
@ ওয়াল কেন extern "C"আনুষ্ঠানিকভাবে প্রয়োজনীয় তার বিশদগুলির জন্য দেখুন [dcl.link]"ডিআইআরেন্ট ভাষা সংযোগের সাথে দুটি ফাংশনের প্রকারগুলি অন্যথায় অভিন্ন হলেও এমনকি আলাদা ধরণের" " এবং [expr.call]"একটি ফাংশনকে একটি অভিব্যক্তির মাধ্যমে কল করা যার ফাংশনের ধরণটি ডায়রেন্ট নামে পরিচিত ফাংশনটির de ition জাতীয় ফাংশনের ধরণের ফলাফল থেকে অবর্ণনীয় আচরণের ফলস্বরূপ হয়"
বেন ভয়েগট

-1

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


6
এটাই কি আমনের জবাব না?
দ্রোঞ্জ

1
@ দ্রোঞ্জ দ্বিতীয়বার পড়ার পরে, হ্যাঁ, এটি বেশিরভাগই। আমি পড়ার সাথে সাথে staticআমি এটিকে একটি পদ্ধতি হিসাবে দেখেছি এবং কোনও কারণে বুঝতে পারি নি যে এটি thisপ্রথম যুক্তি হিসাবে পয়েন্টারটি পাস করে না (এবং এটি std::bindআরও শক্তিশালী ব্যবহারের জন্য নিম্নলিখিত বিতর্ক )। তবে হ্যাঁ, আপনি একেবারে ঠিক বলেছেন! (দ্বিগুণ উত্তরের জন্য দুঃখিত!)
যিশু আলোনসো آباد

3
হ্যাঁ, staticএর কমপক্ষে তিনটি আলাদা, স্বতন্ত্র অর্থ রয়েছে। আপনি যদি যত্নবান না হন তবে আপনি সেগুলি মিশিয়ে ফেলবেন। আমি বলব, এটির বিভিন্ন ব্যবহারের মধ্যে পার্থক্য বুঝতে সত্যই সহায়ক static, কারণ প্রত্যেকে তার নিজের মতো করে একটি দুর্দান্ত সরঞ্জাম।
মাস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.