সি থেকে সি ++ ফাংশনটি কীভাবে কল করবেন?


84

আমি এটা জানি.

সি ++ থেকে সি ফাংশন কল করা হচ্ছে:

যদি আমার অ্যাপ্লিকেশনটি সি ++ এ থাকত এবং আমাকে সি লেখা একটি লাইব্রেরি থেকে ফাংশনগুলি কল করতে হত তবে আমি ব্যবহার করতে পারতাম

//main.cpp

extern "C" void C_library_function(int x, int y);//prototype
C_library_function(2,4);// directly using it.

এটি নামটি C_library_functionকাটাবে না এবং লিঙ্কার তার ইনপুট * .lib ফাইলগুলিতে একই নামটি খুঁজে পাবে এবং সমস্যাটি সমাধান হয়ে গেছে।

সি থেকে সি ++ ফাংশন কল করা হচ্ছে ???

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

যাইহোক আমি এমএসভিসি ব্যবহার করছি



: আপনি সি ++ লাইব্রেরি নিয়ন্ত্রণ যখন stackoverflow.com/questions/12615683/...
郝海东冠状病六四事件法轮功সিরো Santilli

উত্তর:


95

আপনার সি ++ কোডের কার্যকারিতাটি প্রকাশ করার জন্য আপনাকে একটি সিআইপি তৈরি করতে হবে। মূলত, আপনাকে সি ++ কোড লিখতে হবে যা বাহ্যিক "সি" হিসাবে ঘোষিত হয় এবং এতে একটি খাঁটি সি এপিআই থাকে (উদাহরণস্বরূপ ক্লাস ব্যবহার করা হয় না) যা সি ++ গ্রন্থাগারকে আবৃত করে। তারপরে আপনি তৈরি করেছেন খাঁটি সি র‌্যাপার লাইব্রেরি ব্যবহার করুন।

আপনার সি এপিআই বিকল্পভাবে কোনও বস্তু-কেন্দ্রিক স্টাইল অনুসরণ করতে পারে, যদিও সি বস্তু-ভিত্তিক নয়। প্রাক্তন:

 // *.h file
 // ...
 #ifdef __cplusplus
 #define EXTERNC extern "C"
 #else
 #define EXTERNC
 #endif

 typedef void* mylibrary_mytype_t;

 EXTERNC mylibrary_mytype_t mylibrary_mytype_init();
 EXTERNC void mylibrary_mytype_destroy(mylibrary_mytype_t mytype);
 EXTERNC void mylibrary_mytype_doit(mylibrary_mytype_t self, int param);

 #undef EXTERNC
 // ...


 // *.cpp file
 mylibrary_mytype_t mylibrary_mytype_init() {
   return new MyType;
 }

 void mylibrary_mytype_destroy(mylibrary_mytype_t untyped_ptr) {
    MyType* typed_ptr = static_cast<MyType*>(untyped_ptr);
    delete typed_ptr;
 }

 void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) {
    MyType* typed_self = static_cast<MyType*>(untyped_self);
    typed_self->doIt(param);
 }

ধন্যবাদ !! বুঝেছি. parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6
নখর

4
আপনি কিভাবে চূড়ান্ত এক্সিকিউটেবল লিঙ্ক করবেন? আপনি কি সি বা সি ++ ব্যবহার করেন? (আমি যখন সি ব্যবহার করেছি, লিঙ্কারটি সি ++ ফাংশনটি খুঁজে পেল না; যখন আমি সি ++ ব্যবহার করতাম, লিঙ্কারটি std :: cout খুঁজে পেত না))
জ্যাক

4
@ জ্যাক আপনি যদি সি ++ সংকলক / লিংক দিয়ে একটি স্থির লাইব্রেরি তৈরি করেন যা ট্রানসিটিভর সাথে তার নির্ভরতা অন্তর্ভুক্ত করে (সি ++ স্ট্যান্ডার্ড লাইব্রেরি সহ যা আপনার লিঙ্কারের দ্বারা স্পষ্টভাবে লিঙ্ক করা যেতে পারে), আপনি সেই স্ট্যাটিক লাইব্রেরিকে সি কোডের সাথে লিঙ্ক করতে সক্ষম হবেন একটি ব্যবহার করে সি সংকলক / লিঙ্কার।
মাইকেল অ্যারন সাফিয়ান

আপনি কি C ++ থেকে C তে কোনও টেম্পলেট রফতানি করতে পারবেন?
মারকাসজে

আমার একটি "হাইব্রিড" আচরণ রয়েছে কারণ আমার লাইব্রেরিটি সি ++ এবং সি কোড উভয় দিয়ে ডাকতে হবে। ইন *.cpp fileআমিও মধ্যে ফাংশন মোড়ানো করা প্রয়োজন #ifdef _cplusplus+ + extern "C"লিংক সময়ে ত্রুটিগুলি "অনির্ধারিত রেফারেন্স" এড়ানো।
কনকনপ

43

আমি এটি নিম্নলিখিত উপায়ে করব:

(যদি এমএসভিসির সাথে কাজ করে থাকে তবে জিসিসি সংকলনের আদেশগুলি উপেক্ষা করুন)

মনে করুন যে আমার কাছে AAA নামের একটি সি ++ ক্লাস রয়েছে, এটি aaa.h, aaa.cpp ফাইলগুলিতে সংজ্ঞায়িত হয়েছে এবং ক্লাস AAA এর একটি পদ্ধতি sayHi (কনস্ট চর * নাম) রয়েছে যা আমি সি কোডের জন্য সক্ষম করতে চাই।

এএএ শ্রেণির সি ++ কোড - খাঁটি সি ++, আমি এটিকে সংশোধন করি না:

aaa.h

#ifndef AAA_H
#define AAA_H

class AAA {
    public:
        AAA();
        void sayHi(const char *name);
};

#endif

aaa.cpp

#include <iostream>

#include "aaa.h"

AAA::AAA() {
}

void AAA::sayHi(const char *name) {
    std::cout << "Hi " << name << std::endl;
}

এই ক্লাসটি নিয়মিত সি ++ এর জন্য করা হিসাবে সংকলন করা হচ্ছে। এই কোডটি "জানেন না" এটি সি কোড দ্বারা ব্যবহৃত হতে চলেছে। কমান্ডটি ব্যবহার করে:

g++ -fpic -shared aaa.cpp -o libaaa.so

এখন, সি ++ তেও সি সংযোগকারী তৈরি করুন। এটি aaa_c_connector.h, aaa_c_connector.cpp ফাইলগুলিতে সংজ্ঞায়িত করা হচ্ছে । এই সংযোজকটি AAA_sayHi (কাস্টেন্ট চর * নাম) নামে একটি সি ফাংশন সংজ্ঞায়িত করতে চলেছে , এটি এএএর উদাহরণ ব্যবহার করবে এবং এর পদ্ধতিটি কল করবে:

aaa_c_connector.h

#ifndef AAA_C_CONNECTOR_H 
#define AAA_C_CONNECTOR_H 

#ifdef __cplusplus
extern "C" {
#endif

void AAA_sayHi(const char *name);

#ifdef __cplusplus
}
#endif


#endif

aaa_c_connector.cpp

#include <cstdlib>

#include "aaa_c_connector.h"
#include "aaa.h"

#ifdef __cplusplus
extern "C" {
#endif

// Inside this "extern C" block, I can implement functions in C++, which will externally 
//   appear as C functions (which means that the function IDs will be their names, unlike
//   the regular C++ behavior, which allows defining multiple functions with the same name
//   (overloading) and hence uses function signature hashing to enforce unique IDs),


static AAA *AAA_instance = NULL;

void lazyAAA() {
    if (AAA_instance == NULL) {
        AAA_instance = new AAA();
    }
}

void AAA_sayHi(const char *name) {
    lazyAAA();
    AAA_instance->sayHi(name);
}

#ifdef __cplusplus
}
#endif

এটি নিয়মিত সি ++ সংকলন কমান্ড ব্যবহার করে আবার সংকলন করুন:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so

এখন আমার কাছে একটি ভাগ করা লাইব্রেরি রয়েছে (libaaa_c_connector.so), এটি সি ফাংশন এএএ_সায়হি (কনস্ট চর * নাম) প্রয়োগ করে । আমি এখন একটি সি প্রধান ফাইল তৈরি করতে এবং এগুলি সমস্ত একসাথে সংকলন করতে পারি:

main.c

#include "aaa_c_connector.h"

int main() {
    AAA_sayHi("David");
    AAA_sayHi("James");

    return 0;
}

এটি একটি সি সংকলন কমান্ড ব্যবহার করে সংকলন করুন:

gcc main.c -L. -laaa_c_connector -o c_aaa

$ পিডাব্লুডি রাখার জন্য আমার এলডি_লিবিআরএইপিএটিএল সেট করতে হবে এবং যদি আমি এক্সিকিউটেবল চালাও / / সি_আআআআআআ , আমি প্রত্যাশিত আউটপুটটি পেয়ে যাব:

Hi David
Hi James

সম্পাদনা:

কিছু লিনাক্স বিতরণে -laaaএবং -lstdc++শেষ সংকলন কমান্ডের জন্যও প্রয়োজনীয় হতে পারে। ধন্যবাদ আলআমকে। মনোযোগের জন্য


4
আপনি এর সাথে লিব লিঙ্ক gcc usecpp.c -L. -laaa_c_connector -Wl,-rpath,. -o c_aaa
পাথটিও

কি usecpp.c?
আলা এম

4
গত সংকলন লাইন হওয়া উচিত: gcc main.c -L. -laaa_c_connector -laaa -lstdc++ -o c_aaa। নোট করুন -laaaএবং-lstdc+++
আলা এম।

@ আলআম। কেউ আমার কোড সম্পাদনা করেছেন এবং এতে পরিবর্তন main.cকরেছেন usecpp.c। আমি কেবল এটিকে ফিরিয়ে দিয়েছি .... অন্য মন্তব্য সম্পর্কে, এটি যেমন হয় তেমন কাজ করা উচিত। দ্বিতীয় সংকলনটি ব্যবহার করে -laaaএবং এটি সম্ভবত যথেষ্ট হওয়া উচিত (আমি এটি 1.5 বছরেরও বেশি আগে লিখেছিলাম, আমি কী করেছি তা খুব ভাল মনে নেই তবে আমি মনে করি পোস্ট দেওয়ার আগে আমি প্রতিটি লাইন পরীক্ষা করেছি)
কিছু

4
ঠিক আছে, পোস্টের শেষে এটি একটি নোট হিসাবে যুক্ত করুন। মনোযোগের জন্য ধন্যবাদ!
SomethingSomething

6

আপনি যদি এটি করতে চান তবে আপনাকে সি ++ এর জন্য একটি র‌্যাপার লিখতে হবে। সি ++ পিছনের দিকে সামঞ্জস্যপূর্ণ তবে সি ফরোয়ার্ড সামঞ্জস্যপূর্ণ নয়।


5

সি ++ এপিআই সি-সামঞ্জস্যপূর্ণ (কোনও শ্রেণি, টেম্পলেট ইত্যাদি নয়) ধরে নেওয়া, আপনি extern "C" { ... }অন্যভাবে যাওয়ার সময় যেমন করেছিলেন তেমনভাবে এটি গুটিয়ে রাখতে পারেন ।

আপনি যদি অবজেক্ট এবং অন্যান্য চতুর সি ++ স্টাফ প্রকাশ করতে চান তবে আপনাকে একটি র‍্যাপার এপিআই লিখতে হবে।


পুরোপুরি নয় ... সি ++ পাঠাগারটি আবার সংকলন করা দরকার।
মাইকেল অ্যারন সাফিয়ান

ওহ না. সি ++ এপিআই পুরোপুরি অবজেক্ট-ভিত্তিক।
নখর

4
@ ক্লাউস, ওওপি-স্টাইলের সি কোড তৈরি করার বিষয়ে আমার নিবন্ধটি দেখুন .. এবং সি ইন্টারফেসের সাহায্যে এই স্টাইলটি ব্যবহার করে একটি মোড়ক লাইব্রেরি তৈরি করুন তবে অন্তর্নিহিত সি ++ বাস্তবায়ন করুন। তারপরে সি ইন্টারফেসের সাথে লিঙ্ক করুন।
মাইকেল অ্যারন সাফিয়ান

আপনি সুইগ, পাইবুস্ট, ... যেমন সমান জিনিসগুলি (এখনও সি এর দিকে নয়) এর মতো মোড়কের 'সরঞ্জামগুলি' দেখে নিতে পারেন
xtofl

2

আপনার সি ++ ফাংশনগুলি বহিরাগত "সি" (ওরফে সি স্টাইলের প্রতীক) হিসাবে রফতানি করুন বা সি ++ লিঙ্কারের জন্য অজস্র রক্ষিত রফতানি প্রতীকগুলি সংজ্ঞায়িত করতে .def ফাইল ফর্ম্যাটটি ব্যবহার করুন যখন এটি সি ++ লাইব্রেরি তৈরি করে, তখন সি লিঙ্কারের এটি পড়তে কোনও সমস্যা হবে না


0
#include <iostream>

//////////////
// C++ code //
//////////////
struct A
{
  int i;
  int j;

  A() {i=1; j=2; std::cout << "class A created\n";}
  void dump() {std::cout << "class A dumped: " << i << ":" << j << std::endl;}
  ~A() {std::cout << "class A destroyed\n";}
};

extern "C" {
  // this is the C code interface to the class A
  static void *createA (void)
  {
    // create a handle to the A class
    return (void *)(new A);
  }
  static void dumpA (void *thisPtr)
  {
    // call A->dump ()
    if (thisPtr != NULL) // I'm an anal retentive programmer
    {
      A *classPtr = static_cast<A *>(thisPtr);
      classPtr->dump ();
    }
  }
  static void *deleteA (void *thisPtr)
  {
    // destroy the A class
    if (thisPtr != NULL)
    {
      delete (static_cast<A *>(thisPtr));
    }
  }
}

////////////////////////////////////
// this can be compiled as C code //
////////////////////////////////////
int main (int argc, char **argv)
{
  void *handle = createA();

  dumpA (handle);
  deleteA (handle);

  return 0;
}

4
আপনার উত্তরের কিছু ব্যাখ্যা যোগ করুন বিবেচনা করুন।
এইচএমডি

একটি সংক্ষিপ্ত ব্যাখ্যা কিভাবে উপরে প্রশ্নের উত্তর অন্যদের কাছে উত্তর আরো উপযোগী করে তোলে।
এসওএস

-3

আপনি বহিরাগত "সি" কীওয়ার্ড সহ ফাংশন ঘোষণার উপসর্গ করতে পারেন, যেমন

বাহ্যিক "সি" ইন্ট মাইকিপ্পাঙ্কশন ()

{

// কোড এখানে যায়

প্রত্যাবর্তন 0;

}

আরও উদাহরণের জন্য আপনি "বাহ্যিক" কীওয়ার্ড সম্পর্কে গুগলে আরও অনুসন্ধান করতে পারেন। আপনার আরও কয়েকটি জিনিস করা দরকার তবে Google এর কাছ থেকে প্রচুর উদাহরণ পাবেন তা অসুবিধা নয়।


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