সি ++ এবং সি এর সংমিশ্রণ - #ifdef __cplusplus কীভাবে কাজ করে?


318

আমি এমন একটি প্রকল্পে কাজ করছি যার প্রচুর উত্তেজনা সি কোড রয়েছে। আমরা শেষ পর্যন্ত উত্তরাধিকারের কোডটি রূপান্তর করার অভিপ্রায় দিয়ে সি ++ তে লেখা শুরু করেছি। সি এবং সি ++ কীভাবে ইন্টারঅ্যাক্ট করে সে সম্পর্কে আমি কিছুটা বিভ্রান্ত । আমি মোড়কে বুঝি যে সি মাধ্যমে কোডের extern "C"সি ++ কম্পাইলার কাপড় ইস্ত্রী করা হবে না সি কোডের নাম, কিন্তু আমি সম্পূর্ণরূপে নিশ্চিত কিভাবে এই বাস্তবায়ন নই।

সুতরাং, প্রতিটি সি হেডার ফাইলের শীর্ষে (অন্তর্ভুক্ত গার্ডদের পরে), আমাদের আছে

#ifdef __cplusplus
extern "C" {
#endif

এবং নীচে, আমরা লিখুন

#ifdef __cplusplus
}
#endif

দুজনের মধ্যে, আমাদের আমাদের অন্তর্ভুক্ত, টাইপডেফস এবং ফাংশন প্রোটোটাইপস রয়েছে। আমি এগুলি সঠিকভাবে বুঝতে পারছি কিনা তা দেখতে আমার কয়েকটি প্রশ্ন রয়েছে:

  1. যদি আমি একটি সি ++ ফাইল A.hh যা অন্তর্ভুক্ত আছে সি হেডার ফাইল BH রয়েছে আরেকটি সি হেডার ফাইল অধ্যায়, কিভাবে কাজ করে? আমি মনে করি যে সংকলকটি যখন ভাতে প্রবেশ __cplusplusকরবে তখন সংজ্ঞায়িত হবে, সুতরাং এটি কোডটি মোড়ানো হবে extern "C" (এবং __cplusplusএই ব্লকের অভ্যন্তরে সংজ্ঞায়িত হবে না)। সুতরাং, যখন এটি সি এ পদক্ষেপ __cplusplusনেবে, সংজ্ঞায়িত হবে না এবং কোডটি মোড়ানো হবে না extern "C"। এটা কি সঠিক?

  2. কোডের টুকরোটি মুড়িয়ে কোনও সমস্যা আছে কি extern "C" { extern "C" { .. } }? দ্বিতীয়টি কী করবে extern "C" ?

  3. আমরা এই মোড়কটি .c ফাইলের চারপাশে রাখি না, কেবলমাত্র .h ফাইলগুলি। সুতরাং, যদি কোনও ক্রিয়ায় প্রোটোটাইপ না থাকে তবে কী হবে? সংকলকটি কি এটি সি ++ ফাংশন বলে মনে করে?

  4. আমরা কিছু তৃতীয় পক্ষের কোডও ব্যবহার করছি যা সি-তে লেখা থাকে এবং এর চারপাশে এই ধরণের মোড়ক নেই। যে কোনও সময় আমি সেই লাইব্রেরি থেকে একটি শিরোলেখ অন্তর্ভুক্ত করি, আমি extern "C"# অন্তর্ভুক্ত এর চারপাশে একটি রাখছি । এটি কি এটি মোকাবেলা করার সঠিক উপায়?

  5. অবশেষে, এটি কি একটি ভাল ধারণা সেট আপ? আমাদের আরও কিছু করা উচিত? আমরা অদূর ভবিষ্যতের জন্য সি এবং সি ++ মিশ্রিত করতে যাচ্ছি , এবং আমি নিশ্চিত করতে চাই যে আমরা আমাদের সমস্ত ঘাঁটি আবরণ করছি।



2
সংক্ষিপ্তভাবে, এটি সর্বোত্তম ব্যাখ্যা: To ensure that the names declared in that portion of code have C linkage, and thus C++ name mangling is not performed. (আমি এটি লিঙ্কটি থেকে পেয়েছি )
anhldbk

আপনাকে সি ভাষার নাম
এডওয়ার্ড কারাক

উত্তর:


290

extern "C"সংকলক কোডটি পড়ার উপায়টি সত্যিই পরিবর্তন করে না। যদি আপনার কোডটি একটি .c ফাইলে থাকে তবে এটি সি হিসাবে সংকলিত হবে, যদি এটি একটি .cpp ফাইলে থাকে তবে এটি সি ++ হিসাবে সংকলিত হবে (যদি আপনি আপনার কনফিগারেশনে কোনও অদ্ভুত কিছু না করেন)।

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

এর মধ্যে কোডটি extern "C"এখনও সি ++ কোড। আপনি একটি বাহ্যিক "সি" ব্লকে কী করতে পারেন তার সীমাবদ্ধতা রয়েছে তবে তারা লিঙ্কেজ সম্পর্কে সমস্ত কিছু। আপনি কোনও নতুন প্রতীক সংজ্ঞায়িত করতে পারবেন না যা সি লিঙ্কেজের সাহায্যে তৈরি করা যায় না। এর অর্থ কোনও শ্রেণি বা টেম্পলেট নয়, উদাহরণস্বরূপ।

extern "C"সুন্দরভাবে বাসা বাঁধে। এছাড়াও আছে extern "C++"যদি আপনি নিজে খুঁজে একেবারে ভেতরে আটকা পড়ে extern "C"অঞ্চল, কিন্তু এটি একটি পরিচ্ছন্নতা দৃষ্টিকোণ থেকে যেমন একটি ভাল ধারণা না।

এখন, বিশেষত আপনার সংখ্যাযুক্ত প্রশ্ন সম্পর্কিত:

# 1 সম্পর্কিত: __cplusplus extern "C"ব্লকের ভিতরে সংজ্ঞায়িত থাকবে । যদিও এতে ব্লকগুলি খুব সুন্দরভাবে বাসা বেঁধে নেওয়া উচিত নয়।

# 2 সম্পর্কিত: __cplusplus সি ++ সংকলকটির মধ্য দিয়ে চলমান যে কোনও সংকলন ইউনিটের জন্য সংজ্ঞায়িত করা হবে। সাধারণত, এর অর্থ .cpp ফাইল এবং যে কোনও ফাইল সেই .cpp ফাইলের অন্তর্ভুক্ত থাকে। একই .h (বা .এইচ বা। এইচপি বা আপনার কী আছে) বিভিন্ন সময়ে সি বা সি ++ হিসাবে ব্যাখ্যা করা যেতে পারে, যদি বিভিন্ন সংকলন ইউনিট তাদের অন্তর্ভুক্ত করে। আপনি যদি .h ফাইলে প্রোটোটাইপগুলি সি চিহ্নের নাম উল্লেখ করতে চান তবে তাদের অবশ্যই extern "C"সি ++ হিসাবে ব্যাখ্যা করার সময় থাকতে হবে এবং সি হিসাবে ব্যাখ্যা করার সময় তাদের এগুলি থাকা উচিত নয় extern "C"hence তাই #ifdef __cplusplusচেক করা।

আপনার প্রশ্নের উত্তর # 3: প্রোটোটাইপ ব্যতীত ফাংশনগুলির C ++ লিঙ্কেজ থাকবে যদি তারা কোনও extern "C"ব্লকের ভিতরে না থাকে .cpp ফাইলগুলিতে থাকে । এটি ঠিক আছে, কারণ এটির কোনও প্রোটোটাইপ না থাকলে এটি কেবল একই ফাইলে অন্য ফাংশনগুলি দ্বারা ডাকা যেতে পারে এবং তারপরে যোগসূত্রটি কেমন দেখাচ্ছে তা আপনি সাধারণত যত্নশীল হন না কারণ আপনি সেই ফাংশনটি রাখার পরিকল্পনা করছেন না because যাইহোক যাইহোক একই সংকলনের ইউনিটের বাইরে যে কোনও কিছু দ্বারা কল করা উচিত।

# 4 এর জন্য, আপনি ঠিক পেয়েছেন। আপনি যদি সি লিঙ্কেজ (যেমন একটি সি সংকলক দ্বারা সংকলিত কোড) এর কোডের জন্য একটি শিরোলেখ অন্তর্ভুক্ত করছেন তবে আপনাকে অবশ্যই extern "C"শিরোনাম করতে হবে - এইভাবে আপনি লাইব্রেরির সাথে লিঙ্ক করতে সক্ষম হবেন। (অন্যথায়, আপনার লিঙ্কার নামগুলির সাথে ফাংশনগুলি সন্ধান করবে যেমন _Z1hicআপনি কখন সন্ধান করেছিলেনvoid h(int, char)

5: এই ধরণের মিশ্রণটি ব্যবহার করার একটি সাধারণ কারণ extern "C"এবং আমি এইভাবে এটি করাতে কোনও ভুল দেখতে পাচ্ছি না - কেবল আপনি কী করছেন তা আপনি বুঝতে পেরেছেন তা নিশ্চিত করুন।


10
extern "C++"যখন আপনার সি ++ শিরোনাম / কোডটি কোনও সি কোডের অভ্যন্তরে আটকা পড়ে থাকে তখন উল্লেখ করার জন্য ভাল
ডিডেবেমে

1
আমি একটি সাধারণ সি প্রোগ্রাম লিখেছি। এর অভ্যন্তরে আমি #ifdef __cplusplus ব্লক যুক্ত করেছি এবং একটি প্রিন্টফ ("__ সিপিপ্লসপ্লাস সংজ্ঞায়িত \ n") যুক্ত করেছি; এটা. যদি আমি এটি জিসিসি দিয়ে সংকলন করি, "__cplusplus Defised" মুদ্রিত হয় না, তবে আমি যদি এটি g ++ দিয়ে সংকলন করি তবে এটি মুদ্রিত হয়। সুতরাং আমি চিত্র __cplusplus অর্থ সংকলকটি সি ++ সংকলক (আপনি এটি বলেছিলেন)। এটা ঠিক না? (কারণ আমি আপনাকে বলতে দেখেছি '__cplsplus এর বাহ্যিক "C" ব্লকের ভিতরে সংজ্ঞা দেওয়া উচিত। আমরা __cplplus স্পষ্টভাবে সংজ্ঞায়িত করতে পারি?
চ্যান কিম

1
আপনি যে কোনও কিছুর (প্রায়) সংজ্ঞা দিতে সক্ষম হবেন, এর সম্পূর্ণ বিন্দুটি __cplusplusহ'ল C++বনাম ব্যবহার করা হচ্ছে কিনা তা নির্ধারণ করা C, সুতরাং এটির ম্যানুয়ালি / স্পষ্টরূপে এটির উদ্দেশ্যকে
অস্বীকার

বাহ্যিক "সি" প্রকৃতপক্ষে সংকলক উত্স ফাইলটি কীভাবে দেখে তা নয়, এটি শিরোনাম ফাইলটি কীভাবে দেখে about সি বনাম সি ++ হিসাবে সংকলিত হওয়ার সময় স্ট্রাক্টগুলির বিভিন্ন আকার থাকতে পারে, নামটির ম্যাঙ্গলিং অবশ্যই রয়েছে এবং সম্ভাব্য অন্যান্য পার্থক্যও রয়েছে।
নিক

39
  1. extern "C"__cplusplusম্যাক্রো উপস্থিতি বা অনুপস্থিতি পরিবর্তন করে না । এটি কেবল মোড়ানো ঘোষণার লিঙ্কেজ এবং নাম-ম্যাংলিংয়ের পরিবর্তন করে।

  2. আপনি extern "C"ব্লক করতে পারেন বেশ আনন্দের সাথে।

  3. আপনি যদি আপনার .cফাইলগুলি সি ++ হিসাবে সংকলন করেন তবে কোনও extern "C"ব্লকের মধ্যে নেই এবং extern "C"প্রোটোটাইপ ব্যতীত সি ++ ফাংশন হিসাবে বিবেচনা করা হবে। আপনি যদি সেগুলিকে সি হিসাবে সংকলন করেন তবে অবশ্যই সবকিছুই একটি সি ফাংশন হবে।

  4. হ্যাঁ

  5. আপনি নিরাপদে এইভাবে সি এবং সি ++ মিশ্রিত করতে পারেন।


আপনি যদি .cফাইলগুলিকে সি ++ হিসাবে সংকলন করেন তবে সমস্ত কিছু সি ++ কোড হিসাবে সংকলিত হয়, এমনকি এটি কোনও extern "C"ব্লকের মধ্যে রয়েছে। extern "C"কোড বৈশিষ্ট্য সি ++ কলিং নিয়মাবলী (যেমন অপারেটর ওভারলোডিং) কিন্তু ফাংশন শরীরের নির্ভর এখনও সি হিসাবে কম্পাইল করা হয় ++, ব্যবহার করতে পারবেন না যে সব অনিবার্য ফল দিয়ে।
ডেভিড সি

21

অ্যান্ড্রু শেলানস্কির দুর্দান্ত উত্তরের এবং কিছুটা দ্বিমত পোষণ করার জন্য কয়েকটি পাঠ্যসূচি যা সংকলকটি কোডটি পড়েন তা সত্যিই বদলে না

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

সংকলক ত্রুটিগুলি যদি আপনি ওভারলোডিংয়ের মতো প্রোটোটাইপ ঘোষণার সি ++ বৈশিষ্ট্যগুলি ব্যবহার করার চেষ্টা করেন।

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

C ++ সেটিং হিসাবে সংকলন সি ব্যবহার থেকে লোককে নিরুৎসাহিত করার একটি কারণ হ'ল এর অর্থ তাদের উত্স কোডটি আর পোর্টেবল নয়। সেটিংটি একটি প্রকল্প সেটিং এবং সুতরাং যদি একটি .c ফাইল অন্য কোনও প্রকল্পে ফেলে দেওয়া হয় তবে এটি সি ++ হিসাবে সংকলিত হবে না। আমি বরং লোকেরা .cpp এ ফাইল প্রত্যয়টির নাম পরিবর্তন করতে সময় নিই।


1
এটি ছিল ক্রিপ্টিক কারণ, আমার চুলগুলি বাইরে টানতে। সত্যিই কোথাও পোস্ট করা দরকার।
মিচেল কারি

3

এটি এবিআই সম্পর্কে, যাতে সি এবং সি ++ অ্যাপ্লিকেশন কোনও সমস্যা ছাড়াই সি ইন্টারফেস ব্যবহার করতে দেয়।

যেহেতু সি ভাষাটি খুব সহজ, কোড জেনারেশন বিভিন্ন সংকলক যেমন জিসিসি, বোরল্যান্ড সি \ সি ++, এমএসভিসি ইত্যাদির জন্য বহু বছরের জন্য স্থিতিশীল ছিল code

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

লোকেরা এখনও সি ++ এ প্রকৃত প্রোগ্রামটি প্রয়োগ করতে পছন্দ করতে পারে তবে এখনও পুরানো সি ইন্টারফেস এবং এবিআইকে যথারীতি বজায় রাখতে পারে, শিরোনাম ফাইলটি বহিরাগত "সি" { declare ঘোষণা করতে হবে, এটি সংকলকটি সামঞ্জস্যপূর্ণ / পুরানো / সাধারণ / সহজ সি এবিআইকে জানায় ইন্টারফেস ফাংশনগুলির জন্য যদি সংকলক সি সংকলক হয় না সি ++ সংকলক।

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