সি ++ তে বাহ্যিক "সি" এর প্রভাব কী?


1629

extern "C"সি ++ কোডে ঠিক কী করা যায়?

উদাহরণ স্বরূপ:

extern "C" {
   void foo();
}

82
আমি আপনাকে এই নিবন্ধটি প্রবর্তন করতে চাই: http://www.agner.org/optimize/calling_conventions.pdf এটি আপনাকে কনভেনশন কল করার এবং কম্পাইলারগুলির মধ্যে পার্থক্য সম্পর্কে আরও অনেক কিছু বলে।
স্যাম লিয়াও

1
@ লিটারাম আমার মাথার উপরের অংশে, এটি সংকলকটিকে সি ব্যবহার করে কোডের স্কোপটি সংকলন করতে বলছে, আপনার ক্রস-সংকলক রয়েছে given এছাড়াও, এর অর্থ হ'ল আপনার কাছে একটি সিপিপি ফাইল রয়েছে যেখানে আপনার সেই foo()ফাংশন রয়েছে।
ha9u63ar

1
@ ha9u63ar এটি 'আমার মাথার উপরের অংশ'। আপনার সম্পূর্ণ মন্তব্যটিও ভুল। আমি আপনাকে এটি মুছে ফেলার পরামর্শ দিচ্ছি।
টামাএমসিগ্লিন

উত্তর:


1555

বাহ্যিক "সি" সি ++ এ একটি ফাংশন-নাম তৈরি করে 'সি' লিঙ্কেজ রয়েছে (সংকলক নামটি ছাঁটাই করে না) যাতে ক্লায়েন্ট সি কোডটি একটি 'সি' সামঞ্জস্যপূর্ণ শিরোলেখ ফাইলটি ব্যবহার করে আপনার ফাংশনটিতে লিঙ্ক করতে পারে (যেমন ব্যবহার করতে পারে) যা কেবলমাত্র আপনার ফাংশন ঘোষণা। আপনার ফাংশন সংজ্ঞাটি একটি বাইনারি বিন্যাসে অন্তর্ভুক্ত রয়েছে (এটি আপনার সি ++ সংকলক দ্বারা সংকলিত হয়েছিল) যে ক্লায়েন্ট 'সি' লিঙ্কার তারপরে 'সি' নামটি ব্যবহার করে লিঙ্ক করবে।

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

কেবলমাত্র আপনি জানেন, আপনি প্রতিটি পৃথক ঘোষণা / সংজ্ঞা স্পষ্টভাবে "সি" লিঙ্কেজ নির্দিষ্ট করতে পারেন বা নির্দিষ্ট লিঙ্কেজের জন্য ঘোষণাগুলি / সংজ্ঞাগুলির ক্রমকে গ্রুপ করতে ব্লক ব্যবহার করতে পারেন:

extern "C" void foo(int);
extern "C"
{
   void g(char);
   int i;
}

আপনি যদি প্রযুক্তিগুলির বিষয়ে যত্নশীল হন তবে সেগুলি C ++ 03 স্ট্যান্ডার্ডের 7.5 বিভাগে তালিকাভুক্ত করা হয়েছে, এখানে একটি সংক্ষিপ্ত সারাংশ দেওয়া হয়েছে (বাহ্যিক "সি" তে জোর দিয়ে):

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

21
সি সংকলক মাংলিং ব্যবহার করে না যা সি ++ এর কাজ করে। সুতরাং আপনি যদি একটি সি ++ প্রোগ্রাম থেকে এসি ইন্টারফেস কল করতে চান, আপনাকে পরিষ্কারভাবে ঘোষণা করতে হবে যে সি ইন্টারফেসটি "এক্সটার্নার সি" হিসাবে।
স্যাম লিয়াও

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

8
'বাহ্যিক "সি" একটি ফাংশনকে বাহ্যিক সংযোগ রাখতে বাধ্য করে (এটি স্থির করতে পারে না)' ভুল। 'স্থির' ভিতরে 'বাহ্যিক "সি" "বৈধ; ঘোষিত একটি সত্তার অভ্যন্তরীণ লিঙ্কেজ রয়েছে এবং তাই কোনও ভাষা সংযোগ নেই।
রিচার্ড স্মিথ

14
'সমস্ত ফাংশনের ধরণ, ফাংশন নাম এবং ভেরিয়েবল নামের একটি ভাষার যোগসূত্র রয়েছে' এছাড়াও ভুল। কেবলমাত্র ফাংশনের নাম এবং বহিরাগত সংযোগ সহ পরিবর্তনশীল নামেরগুলির একটি ভাষার লিঙ্কেজ রয়েছে।
রিচার্ড স্মিথ

9
নোট যে extern "C" { int i; }একটি সংজ্ঞা। এটি আপনি নির্ধারিত সংজ্ঞা ছাড়াই নাও করতে পারেন void g(char);। এটি একটি সংজ্ঞা হিসাবে তৈরি করতে আপনার প্রয়োজন হবে extern "C" { extern int i; }। অন্যদিকে, ধনুর্বন্ধনী ছাড়া এক-ঘোষণা সিনট্যাক্স ঘোষণা একটি অ-সংজ্ঞা বর্ননা করেন, extern "C" int i;হিসাবে একইextern "C" { extern int i; }
aschepler

327

আমি কিছুটা তথ্য যুক্ত করতে চেয়েছিলাম, যেহেতু এটি এখনও পোস্ট করা হয়নি।

আপনি প্রায়শই সি এর শিরোনামে কোড দেখতে পাবেন:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

এটি যা অর্জন করে তা হ'ল এটি আপনাকে সেই সি হেডার ফাইলটি আপনার সি ++ কোডের সাথে ব্যবহার করতে দেয়, কারণ ম্যাক্রো "__cplusplus" সংজ্ঞায়িত করা হবে। কিন্তু আপনি করতে পারেন এছাড়াও এখনও আপনার উত্তরাধিকার সি কোড, যেখানে ম্যাক্রো সঙ্গে এটি ব্যবহার না সংজ্ঞায়িত, তাই এটি স্বতন্ত্র সি ++ কনস্ট্রাক্ট দেখতে পাবেন না।

যদিও, আমি সি ++ কোডও দেখেছি যেমন:

extern "C" {
#include "legacy_C_header.h"
}

যা আমি কল্পনা করি একই জিনিসটি সফল করে তোলে।

কোন উপায়টি ভাল তা নিশ্চিত নয়, তবে আমি উভয়ই দেখেছি।


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

8
@ অ্যান: সি ++ সংকলকটি অচিরাচরিত নামও সন্ধান করবে, কারণ এটি extern "C"শিরোনামে দেখেছিল )। এটি দুর্দান্ত কাজ করে, এই কৌশলটি বহুবার ব্যবহার করে।
বেন ভয়েগট

20
@ অ্যান: এটি ঠিক নেই, প্রথমটিও ঠিক আছে। এটি সি সংকলক দ্বারা উপেক্ষা করা হয়েছে, এবং সি ++ এ দ্বিতীয় হিসাবে একই প্রভাব রয়েছে। সংকলকটির শিরোনামটি extern "C"অন্তর্ভুক্ত হওয়ার আগে বা পরে এটির মুখোমুখি হয় কিনা তা কম যত্ন নিতে পারে না । সংকলকটি পৌঁছানোর সময়, এটি যাইহোক প্রিপ্রোসেসড পাঠ্যের কেবল একটি দীর্ঘ স্ট্রিম।
বেন ভয়েগট

8
@ অ্যান, না, আমি মনে করি আপনি উত্সের অন্য কোনও ত্রুটি দ্বারা প্রভাবিত হয়েছেন, কারণ আপনি যা বর্ণনা করছেন তা ভুল। g++কমপক্ষে গত ১ years বছরে যে কোনও সময় কোনও লক্ষ্য হিসাবে এটির কোনও সংস্করণ পাওয়া যায় নি wrong প্রথম উদাহরণটির পুরো বিষয়টি হ'ল আপনি সি বা সি ++ সংকলক ব্যবহার করেন কিনা তা বিবেচ্য নয়, extern "C"ব্লকের নামগুলির জন্য কোনও নাম ম্যাঙ্গালিং করা হবে না ।
জোনাথন ওয়াকলি

7
"কোনটি আরও ভাল" - অবশ্যই, প্রথম বৈকল্পিকটি আরও ভাল: এটি সি এবং সি ++ কোড উভয় প্রয়োজনীয়তার বাইরে সরাসরি শিরোনাম সহ মঞ্জুরি দেয়। দ্বিতীয় পদ্ধতিটি সি শিরোনামগুলির পক্ষে এক কার্যকারিতা যা লেখক সি ++ রক্ষীদের ভুলে গেছেন (কোনও সমস্যা নেই, যদিও পরে যদি এগুলি যুক্ত করা হয় তবে নেস্টেড বাহ্যিক "সি" ঘোষণা গৃহীত হয় ...)।
অ্যাকনকাগুয়া

267

g++কী চলছে তা দেখার জন্য একটি উত্পন্ন বাইনারি সাজান

main.cpp

void f() {}
void g();

extern "C" {
    void ef() {}
    void eg();
}

/* Prevent g and eg from being optimized away. */
void h() { g(); eg(); }

উত্পন্ন ELF আউটপুট সংকলন এবং বিচ্ছিন্ন করুন :

g++ -c -std=c++11 -Wall -Wextra -pedantic -o main.o main.cpp
readelf -s main.o

আউটপুট রয়েছে:

     8: 0000000000000000     7 FUNC    GLOBAL DEFAULT    1 _Z1fv
     9: 0000000000000007     7 FUNC    GLOBAL DEFAULT    1 ef
    10: 000000000000000e    17 FUNC    GLOBAL DEFAULT    1 _Z1hv
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z1gv
    13: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND eg

ব্যাখ্যা

আমরা দেখতে পাচ্ছি:

  • efএবং egকোড হিসাবে একই নামের চিহ্ন সহ সংরক্ষণ করা হয়েছিল

  • অন্যান্য চিহ্নগুলি ম্যাঙ্গেল করা হয়েছিল। আসুন এগুলিকে অবিচ্ছিন্ন করুন:

    $ c++filt _Z1fv
    f()
    $ c++filt _Z1hv
    h()
    $ c++filt _Z1gv
    g()

উপসংহার: নিম্নলিখিত উভয় প্রতীক ধরণের ম্যাংগল ছিল না :

  • সংজ্ঞায়িত
  • Ndx = UNDলিঙ্কে সরবরাহ করা বা অন্য অবজেক্ট ফাইল থেকে রান সময় হিসাবে ঘোষিত তবে অপরিজ্ঞিত ( ) ঘোষণা করা হয়েছে

সুতরাং extern "C"কল করার সময় আপনার উভয়ের প্রয়োজন হবে :

  • সি ++ থেকে সি: g++উত্পাদিত অবিচ্ছিন্ন প্রতীকগুলি আশা করতে বলুনgcc
  • সি থেকে সি ++: ব্যবহারের g++জন্য অবিরাম চিহ্ন তৈরি করতে বলুনgcc

যে জিনিসগুলি বহিরাগত সি তে কাজ করে না

এটি সুস্পষ্ট হয়ে যায় যে যে কোনও সি ++ বৈশিষ্ট্য যাতে নাম ম্যাংলিংয়ের প্রয়োজন হয় তা ভিতরে কাজ করবে না extern C:

extern "C" {
    // Overloading.
    // error: declaration of C function ‘void f(int)’ conflicts with
    void f();
    void f(int i);

    // Templates.
    // error: template with C linkage
    template <class C> void f(C i) { }
}

সি ++ উদাহরণ থেকে ন্যূনতম চলমান সি

সম্পূর্ণতার স্বার্থে এবং সেখানে নতুনদের জন্য, আরও দেখুন: একটি সি ++ প্রকল্পে সি উত্স ফাইলগুলি কীভাবে ব্যবহার করবেন?

সি ++ থেকে সি কল করা বেশ সহজ: প্রতিটি সি ফাংশনে কেবল একটি সম্ভাব্য অ-মাংগেল্ড প্রতীক থাকে, সুতরাং অতিরিক্ত কোনও কাজের প্রয়োজন হয় না।

main.cpp

#include <cassert>

#include "c.h"

int main() {
    assert(f() == 1);
}

সিএইচ

#ifndef C_H
#define C_H

/* This ifdef allows the header to be used from both C and C++ 
 * because C does not know what this extern "C" thing is. */
#ifdef __cplusplus
extern "C" {
#endif
int f();
#ifdef __cplusplus
}
#endif

#endif

সিসি

#include "c.h"

int f(void) { return 1; }

চালান:

g++ -c -o main.o -std=c++98 main.cpp
gcc -c -o c.o -std=c89 c.c
g++ -o main.out main.o c.o
./main.out

extern "C"লিঙ্ক ব্যতীত ব্যর্থ:

main.cpp:6: undefined reference to `f()'

কারণ g++একটি ম্যাঙ্গলেড f, যা gccউত্পাদন করেনি খুঁজে প্রত্যাশা করে।

গিটহাবের উপর উদাহরণ

সি উদাহরণ থেকে ন্যূনতম চলমান সি ++

সি থেকে সি ++ কল করা কিছুটা শক্ত: আমাদের প্রতিটি ফাংশন ম্যানুয়ালি তৈরি করতে হবে যা আমরা প্রকাশ করতে চাই।

এখানে আমরা চিত্রিত করি যে কীভাবে সি ++ ফাংশন ওভারলোডগুলি সি তে প্রকাশ করা যায় to

main.c

#include <assert.h>

#include "cpp.h"

int main(void) {
    assert(f_int(1) == 2);
    assert(f_float(1.0) == 3);
    return 0;
}

cpp.h

#ifndef CPP_H
#define CPP_H

#ifdef __cplusplus
// C cannot see these overloaded prototypes, or else it would get confused.
int f(int i);
int f(float i);
extern "C" {
#endif
int f_int(int i);
int f_float(float i);
#ifdef __cplusplus
}
#endif

#endif

cpp.cpp

#include "cpp.h"

int f(int i) {
    return i + 1;
}

int f(float i) {
    return i + 2;
}

int f_int(int i) {
    return f(i);
}

int f_float(float i) {
    return f(i);
}

চালান:

gcc -c -o main.o -std=c89 -Wextra main.c
g++ -c -o cpp.o -std=c++98 cpp.cpp
g++ -o main.out main.o cpp.o
./main.out

ছাড়া extern "C"এটি দিয়ে ব্যর্থ হলে:

main.c:6: undefined reference to `f_int'
main.c:7: undefined reference to `f_float'

কারণ g++তৈরি ম্যাঙ্গেলড প্রতীক যা gccখুঁজে পায় না।

গিটহাবের উপর উদাহরণ

উবুন্টুতে পরীক্ষিত 18.04।


21
সর্বোত্তম উত্তর যেহেতু আপনি ১) স্পষ্টভাবে উল্লেখ করেছেন extern "C" {যা আপনাকে সি ++ প্রোগ্রামের মধ্যে থেকে আনম্যাংলড সি ফাংশনগুলি কল করতে সহায়তা করে পাশাপাশি সি প্রোগ্রামের মধ্যে থাকা আনম্যাঙ্গেল সি ++ ফাংশনগুলি , যা অন্য উত্তরগুলি এত স্পষ্ট করে না এবং 2) কারণ আপনি পৃথক পৃথক উদাহরণ দেখান প্রতিটি। ধন্যবাদ!
গ্যাব্রিয়েল স্ট্যাপলস 25:58

3
আমি এই উত্তরটি খুব পছন্দ করি
সেলফুট বুড়ো

4
সেরা উত্তরটি
হাতছাড়া করায় এটি

1
@ জাভেনিসিপিপিএমসি গোয়ান আপনার কী মনে করে যে আমার একজন সি ++ শিক্ষক ছিল? :-)
সিরো সান্তিলি 法轮功 病毒 审查 六四 事件 法轮功

205

প্রতিটি সি ++ প্রোগ্রামে, সমস্ত অ স্থিত ফাংশনগুলি বাইনারি ফাইলটিতে প্রতীক হিসাবে প্রদর্শিত হয় represented এই চিহ্নগুলি বিশেষ পাঠ্যের স্ট্রিং যা প্রোগ্রামের কোনও ক্রিয়াকে অনন্যভাবে চিহ্নিত করে।

সি-তে, চিহ্নটির নামটি ফাংশন নামের মতো। এটি সম্ভব কারণ সি তে কোনও দুটি অ স্থির ফাংশনের একই নাম থাকতে পারে না।

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

সুতরাং আপনি যদি কোনও ফাংশন বহিরাগত সি হিসাবে নির্দিষ্ট করেন তবে সংকলকটি এর সাথে নাম ম্যাংলিং সম্পাদন করে না এবং এটির ফাংশন নাম হিসাবে এটির প্রতীক নামটি ব্যবহার করে সরাসরি অ্যাক্সেস করা যায়।

ব্যবহার করার সময় dlsym()এবং dlopen()এই জাতীয় ফাংশন কল করার জন্য এটি কার্যকর হয়।


আপনি সহজে বলতে কি বোঝাতে চান? প্রতীক নাম = ফাংশন নাম কি পরিচিত নাম, বা অন্য জিনিস dlsym পাস করা হবে?
ত্রুটি

1
@ ইরর: হ্যাঁ সাধারণ ক্ষেত্রে এটি কেবলমাত্র একটি শিরোনামের ফাইল দেওয়া সি ++ ভাগ করা লাইব্রেরি ড্লোপেন () সক্রিয়ভাবে অসম্ভব। (এক্স ৮86-তে, ইটানিয়াম এবিআই-এর আকারে একটি প্রকাশিত নাম-ম্যাংলিংয়ের স্পেসিফিকেশন রয়েছে যা আমি জানি যে সমস্ত x86 সংকলক সি সি ++ ফাংশনের নামগুলি ম্যাঙ্গেল করতে ব্যবহার করি, তবে ভাষার কোনও কিছুর জন্য এটির প্রয়োজন হয় না))
জোনাথন টোমার

52

প্রক্রিয়াজাতীয় ভাষা থেকে কোনও অবজেক্ট-ভিত্তিক ভাষা তৈরি করতে সি ++ মঙ্গলে ফাংশনগুলির নাম

বেশিরভাগ প্রোগ্রামিং ভাষা বিদ্যমান প্রোগ্রামিং ভাষার উপরে নির্মিত হয় না। সি ++ সি এর শীর্ষে নির্মিত হয় এবং তদ্ব্যতীত এটি প্রক্রিয়াগত প্রোগ্রামিং ভাষা থেকে নির্মিত একটি অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং ভাষা এবং সেই কারণে সি ++ এর মত প্রকাশ রয়েছে extern "C"যা সি এর সাথে পিছনের দিকে সামঞ্জস্যতা সরবরাহ করে provide

আসুন নীচের উদাহরণটি দেখুন:

#include <stdio.h>

// Two functions are defined with the same name
// but have different parameters

void printMe(int a) {
  printf("int: %i\n", a);
}

void printMe(char a) {
  printf("char: %c\n", a);
}

int main() {
  printMe("a");
  printMe(1);
  return 0;
}

এসি সংকলক উপরের উদাহরণটি সংকলন করবে না, কারণ একই ফাংশনটি printMeদু'বার সংজ্ঞায়িত হয়েছে (যদিও তাদের বিভিন্ন পরামিতি int aবনাম রয়েছে char a)।

gcc -o printMe printMe.c &&//PritMe;
1 ত্রুটি মুদ্রণটি একাধিকবার সংজ্ঞায়িত হয়।

একটি সি ++ সংকলক উপরের উদাহরণটি সংকলন করবে। এটি যত্ন করে না যে printMeদুবার সংজ্ঞায়িত হয়েছে।

g ++ -o মুদ্রণমাধ্যমে মুদ্রণপ্রেম && ./printMe;

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

extern "C" "সি সি ফাংশন নামগুলি ম্যাঙ্গেল করবেন না" বলে

যাইহোক, কল্পনা করুন যে আমাদের কাছে একটি "লিগ্যাসি সি ফাইল আছে" নামক "প্যারেন্ট.সি" রয়েছে যা includeঅন্য লিগ্যাসি সি ফাইলগুলি থেকে "প্যারেন্ট এইচ", "চাইল্ড এইচ" ইত্যাদি নামগুলি ব্যবহার করে যদি লিগ্যাসি "প্যারেন্ট.সি" ফাইলটি চালানো হয় If সি ++ কম্পাইলারের মাধ্যমে ফাংশনটির নামগুলি ম্যাঙ্গেল করা হবে এবং তারা আর "প্যারেন্ট এইচ", "চাইল্ড এইচ", ইত্যাদিতে নির্দিষ্ট ফাংশনের নামের সাথে মেলে না - সুতরাং এই বাহ্যিক ফাইলগুলিতে ফাংশনের নামগুলিও প্রয়োজন হবে মাংগাল করা। একটি জটিল সি প্রোগ্রাম জুড়ে ম্যানলিং ফাংশনগুলির নামগুলি, প্রচুর নির্ভরশীলতা সহ, ভাঙা কোডের দিকে নিয়ে যেতে পারে; সুতরাং এমন কীওয়ার্ড সরবরাহ করা সুবিধাজনক হতে পারে যা সি ++ সংকলককে কোনও ফাংশনের নাম ম্যাঙ্গেল না করতে বলতে পারে।

extern "C"শব্দ একটি সি ++ কম্পাইলার বলে করতে ছিন্ন করা (রিনেম) সি ক্রিয়াটি নাম থাকবে না।

উদাহরণ স্বরূপ:

extern "C" void printMe(int a);


extern "C"আমাদের যদি কেবল একটি dllফাইল থাকে তবে আমরা কী তা ব্যবহার করতে পারি না ? আমি বলতে চাইছি যদি আমাদের কাছে কোনও শিরোনাম ফাইল না থাকে এবং কেবল একটি উত্স ফাইল থাকে (কেবল বাস্তবায়ন) এবং ফাংশন পয়েন্টারের মাধ্যমে এর ফাংশনটি ব্যবহার করে। এই অবস্থায় আমরা কেবল ফাংশন ব্যবহার করি (এর নাম নির্বিশেষে)।
ব্যাটলটেষ্ট

@tfmontague, আমার জন্য আপনি এটি সঠিকভাবে পেরেক! সরাসরি মাথায়।
আর্টানিস জেরাতুল

29

কোনও সি-শিরোনামকে কেবলমাত্র বাহ্যিক "সি" এ মোড়ানো দ্বারা সি ++ এর সাথে সামঞ্জস্য করা যায় না। সি-শিরোনামে শনাক্তকারীরা যখন C ++ কীওয়ার্ডগুলির সাথে দ্বন্দ্ব করেন তখন সি ++ সংকলক এ সম্পর্কে অভিযোগ করবেন।

উদাহরণস্বরূপ, আমি নীচের কোডটি জি ++ এ ব্যর্থ দেখেছি:

extern "C" {
struct method {
    int virtual;
};
}

কিন্ডা বোঝায়, কিন্তু সি-কোডটি সি ++ তে পোর্ট করার সময় মনে রাখার মতো কিছু।


14
extern "C"অন্যান্য উত্তর দ্বারা বর্ণিত হিসাবে সি লিঙ্কেজ ব্যবহার করার অর্থ। এর অর্থ এই নয় যে "সামগ্রীগুলি সি হিসাবে সংকলন করুন" বা যে কোনও কিছুই anything int virtual;সি ++ এ অবৈধ এবং বিভিন্ন লিঙ্কেজ নির্দিষ্ট করে তা পরিবর্তন করে না।
এমএম

1
... বা মোড সাধারণত, সিনট্যাক্স ত্রুটিযুক্ত যে কোনও কোড সংকলন করবে না।
ভ্যালেন্টিন হেইনিৎজ

4
@ ভ্যালেন্টিনহিনজিৎস স্বাভাবিকভাবেই, যদিও সি তে সনাক্তকারী হিসাবে "ভার্চুয়াল" ব্যবহার করা একটি বাক্য গঠন ত্রুটি নয়। আমি কেবল এটিই উল্লেখ করতে চেয়েছিলাম যে আপনি এর চারপাশে বাহ্যিক "সি" রেখে কোনও সি হেডার স্বয়ংক্রিয়ভাবে সি ++ এ ব্যবহার করতে পারবেন না ।
স্যান্ডার মার্টেনস

28

এটি কোনও ফাংশনটির সংযোগটি এমনভাবে পরিবর্তন করে যে ফাংশনটি সি থেকে কলযোগ্য হয় অনুশীলনে এর অর্থ হল যে ফাংশনটির নাম ম্যাঙ্গেলড নয় ।


3
ম্যাংলেড শব্দটি সাধারণত ব্যবহৃত হয় ... বিশ্বাস করবেন না যে আমি কখনও এই অর্থ ব্যবহার করে 'সজ্জিত' দেখেছি।
ম্যাথু শার্লে

1
মাইক্রোসফ্ট (অন্তত আংশিক) তাদের ডকুমেন্টেশনে ম্যাঙ্গেল না করে সজ্জিত ব্যবহার করে । এমনকি তারা তাদের সরঞ্জামটিকে আনকোর্ট (ওরফে আন-ম্যাঙ্গেল) নাম রাখে undname
রেনি নিফেনিগার 21

20

লিঙ্ক করার সময় সি-স্টাইলে those ফাংশনগুলির নাম সন্ধান করতে এটি সি ++ সংকলককে অবহিত করে, কারণ লিঙ্কিংয়ের পর্যায়ে সি এবং সি ++ তে সংকলিত ফাংশনগুলির নাম পৃথক।


12

বাহ্যিক "সি" বোঝাতে একটি সি ++ কম্পাইলার দ্বারা স্বীকৃত হওয়া এবং সংকলককে অবহিত করা যে উল্লেখিত ফাংশনটি সি স্টাইলে সংকলিত হয়েছে (বা হতে হবে)। লিঙ্ক করার সময় এটি সি থেকে ফাংশনের সঠিক সংস্করণের সাথে লিঙ্ক করে that


6

আমি dll (ডায়নামিক লিংক লাইব্রেরি) ফাইলগুলি আগে প্রধান () ফাংশনটিকে "রফতানযোগ্য" তৈরি করতে আগে 'বাহ্যিক "সি" ব্যবহার করেছি যাতে এটি পরে dll থেকে অন্য নির্বাহযোগ্য ক্ষেত্রে ব্যবহার করা যায়। আমি যেখানে এটি ব্যবহার করতাম তার উদাহরণ কার্যকর হতে পারে।

ডিএলএল

#include <string.h>
#include <windows.h>

using namespace std;

#define DLL extern "C" __declspec(dllexport)
//I defined DLL for dllexport function
DLL main ()
{
    MessageBox(NULL,"Hi from DLL","DLL",MB_OK);
}

EXE এর

#include <string.h>
#include <windows.h>

using namespace std;

typedef LPVOID (WINAPI*Function)();//make a placeholder for function from dll
Function mainDLLFunc;//make a variable for function placeholder

int main()
{
    char winDir[MAX_PATH];//will hold path of above dll
    GetCurrentDirectory(sizeof(winDir),winDir);//dll is in same dir as exe
    strcat(winDir,"\\exmple.dll");//concentrate dll name with path
    HINSTANCE DLL = LoadLibrary(winDir);//load example dll
    if(DLL==NULL)
    {
        FreeLibrary((HMODULE)DLL);//if load fails exit
        return 0;
    }
    mainDLLFunc=(Function)GetProcAddress((HMODULE)DLL, "main");
    //defined variable is used to assign a function from dll
    //GetProcAddress is used to locate function with pre defined extern name "DLL"
    //and matcing function name
    if(mainDLLFunc==NULL)
    {
        FreeLibrary((HMODULE)DLL);//if it fails exit
        return 0;
    }
    mainDLLFunc();//run exported function 
    FreeLibrary((HMODULE)DLL);
}

4
বাজে। extern "C"এবং __declspec(dllexport)সম্পর্কযুক্ত নয়। প্রাক্তন নিয়ন্ত্রণ প্রতীক সজ্জা, দ্বিতীয়টি রফতানি এন্ট্রি তৈরির জন্য দায়ী। আপনি সি ++ নাম সজ্জা ব্যবহার করে একটি চিহ্নও রফতানি করতে পারেন। এই প্রশ্নের বিন্দুটি পুরোপুরি অনুপস্থিত ছাড়াও কোড নমুনায় অন্যান্য ভুল রয়েছে। একটির জন্য, mainআপনার ডিএলএল থেকে রফতানি কোনও ফেরতের মান ঘোষণা করে না। বা কনভেনশন আহ্বান, এই বিষয়ে। আমদানি করার সময়, আপনি একটি এলোমেলো কলিং কনভেনশন ( WINAPI) বৈশিষ্ট্যযুক্ত করেন , এবং 32-বিট বিল্ডগুলির জন্য ভুল প্রতীক ব্যবহার করেন (হওয়া উচিত _mainবা _main@0)। দুঃখিত, -1।
IInspectable

1
এটি কেবল পুনরাবৃত্তি করেছিল যে আপনি জানেন না, আপনি কী করছেন, তবে এটি এইভাবে করা আপনার পক্ষে লক্ষ্যযুক্ত প্ল্যাটফর্মগুলির কিছু অঘোষিত তালিকার জন্য কাজ করে। আমি আমার আগের মন্তব্যে উত্থাপিত সমস্যাগুলি আপনি সম্বোধন করেন নি। এটি এখনও একটি ডাউন-ভোট, বন্যভাবে ভুল হওয়ার কারণে (আরও কিছু আছে, এটি একটি মন্তব্যে ফিট করে না)।
IInspectable

1
স্ট্যাক ওভারফ্লো প্রকারের উপর একটি উত্তর পোস্ট করা, যা আপনি জানেন যে আপনি কী করছেন। এটি প্রত্যাশিত আপনার "" রান স্ট্যাক দুর্নীতি রোধ করার " প্রয়াস হিসাবে : আপনার ফাংশন স্বাক্ষর টাইপের একটি রিটার্ন মান নির্দিষ্ট করে void*তবে আপনার বাস্তবায়ন কিছুই ফেরায় না। এটি সত্যিই ভাল উড়ে যাবে ...
IInspectable

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

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

5

extern "C"একটি দুটো ঘটনার স্পেসিফিকেশন যা ব্যবহার করা হয় সি ফাংশান কল মধ্যে CPP সোর্স ফাইল । আমরা সি ফাংশনগুলি কল করতে পারি , ভেরিয়েবলগুলি লিখতে পারি এবং শিরোনাম অন্তর্ভুক্ত করতে পারি । বাহ্যিক সত্তায় ফাংশন ঘোষণা করা হয় এবং এটি বাইরে সংজ্ঞায়িত করা হয়। সিনট্যাক্স হয়

ধরন 1:

extern "language" function-prototype

প্রকার 2:

extern "language"
{
     function-prototype
};

উদাহরণ:

#include<iostream>
using namespace std;

extern "C"
{
     #include<stdio.h>    // Include C Header
     int n;               // Declare a Variable
     void func(int,int);  // Declare a function (function prototype)
}

int main()
{
    func(int a, int b);   // Calling function . . .
    return 0;
}

// Function definition . . .
void func(int m, int n)
{
    //
    //
}

3

এই উত্তরটি অধৈর্য / পূরণের সময়সীমার জন্য, কেবল একটি অংশ / সাধারণ ব্যাখ্যা নীচে:

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

তাই
সি ++ নাম mangling সঙ্গে প্রতিটি ফাংশন পরিচয়
সি, এমনকি নাম স্বতন্ত্র mangling ছাড়া প্রতিটি ফাংশন পরিচয়

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

আরও বিস্তারিত / আরও সঠিক উত্তরের জন্য অন্যান্য উত্তরগুলি পড়ুন।


1

সি এবং সি ++ (অর্থাত্, সি .+ থেকে কলিং সি ফাংশন; এবং সি থেকে সি ++ ফাংশন কল করা) মিশ্রণের সময়, সি ++ নাম মংলিং লিঙ্কিংয়ের সমস্যা সৃষ্টি করে। প্রযুক্তিগতভাবে বলতে গেলে, এই সমস্যাটি কেবল তখনই ঘটে যখন কলি ফাংশনগুলি ইতিমধ্যে সম্পর্কিত সংকলকটি ব্যবহার করে বাইনারি (সম্ভবত একটি * .এ একটি লাইব্রেরী ফাইল) মধ্যে সংকলন করা হয়েছে।

সুতরাং আমাদের C ++ এ ম্যাংলিং নামটি অক্ষম করতে বহিরাগত "সি" ব্যবহার করতে হবে।


0

অন্যান্য ভাল উত্তরের সাথে বিরোধ না করে আমি আমার উদাহরণের কিছুটা যোগ করব।

সি ++ কম্পাইলার হুবহু কী করে: এটি সংকলন প্রক্রিয়ায় নামগুলিকে ম্যাঙ্গেল করে, তাই আমাদের সংকলকটিকে চিকিত্সা করার জন্য বলার প্রয়োজন C বাস্তবায়নের জন্য বিশেষভাবে ।

যখন আমরা সি ++ ক্লাস তৈরি করি এবং যুক্ত করি extern "C", তখন আমরা আমাদের সি ++ সংকলককে বলি যে আমরা সি কলিং কনভেনশনটি ব্যবহার করছি।

কারণ (আমরা সি ++ থেকে সি বাস্তবায়ন কল করছি): হয় আমরা সি ++ থেকে সি ফাংশন কল করতে চাই বা সি ++ ফাংশনটি সি থেকে কল করতে চাই (সি ++ ক্লাস ... ইত্যাদি সিতে কাজ করে না)।


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

ঠিক আছে আমার আপনার কথাটি মনে রাখা উচিত - ঠিক আছে
সুসোহন দাশ

-1

সি সংকলক দ্বারা সংকলিত একটি ফাংশন অকার্যকর এফ () এবং সি ++ সংকলক দ্বারা সংকলিত একই নামের শূন্য ফ () সহ একটি ফাংশন একই ফাংশন নয়। আপনি যদি সেই ফাংশনটি সিটিতে লিখেছিলেন এবং তারপরে আপনি এটিকে C ++ থেকে কল করার চেষ্টা করেছিলেন, তবে লিঙ্কারটি সি ++ ফাংশনটি সন্ধান করবে এবং সি ফাংশনটি খুঁজে পাবে না।

বাহ্যিক "সি" সি ++ সংকলককে বলে যে আপনার একটি ফাংশন রয়েছে যা সি সংকলক দ্বারা সংকলিত হয়েছিল। একবার আপনি বলবেন যে এটি সি সংকলক দ্বারা সংকলিত হয়েছিল, সি ++ সংকলক এটি কীভাবে সঠিকভাবে কল করতে পারে তা জানতে পারবে।

এটি সি ++ সংকলককে একটি সি ++ ফাংশন এমনভাবে সংকলন করতে দেয় যাতে সি সংকলক এটি কল করতে পারে। এই ফাংশনটি আনুষ্ঠানিকভাবে একটি সি ফাংশন হবে তবে এটি যেহেতু এটি সি ++ সংকলক দ্বারা সংকলিত হয়েছে সেহেতু এটি সমস্ত সি ++ বৈশিষ্ট্য ব্যবহার করতে পারে এবং এতে সমস্ত সি ++ কীওয়ার্ড রয়েছে।


সি ++ সংকলক একটি extern "C"ফাংশন সংকলন করতে পারে - এবং (কিছু সীমাবদ্ধতার সাপেক্ষে) এটি সি সংকলক দ্বারা সংকলিত কোড দ্বারা কলযোগ্য হবে।
জোনাথন লেফলার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.