C ++ फ़ंक्शन को C से कैसे कॉल करें?


84

मैं यह जानता हूँ।

C ++ से C फ़ंक्शन को कॉल करना:

यदि मेरा आवेदन C ++ में था और मुझे C. में लिखी गई लाइब्रेरी से फ़ंक्शंस को कॉल करना था, तो मैंने उपयोग किया होगा

//main.cpp

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

यह नाम C_library_functionऔर लिंक को नहीं जोड़ देगा। इसके इनपुट में एक ही नाम * .लिब फाइलें और समस्या हल हो जाएगी।

C + C फ़ंक्शन को C से कॉल करना ???

लेकिन यहां मैं एक बड़े एप्लिकेशन का विस्तार कर रहा हूं जो C में लिखा गया है और मुझे एक लाइब्रेरी का उपयोग करने की आवश्यकता है जो C ++ में लिखी गई है। सी ++ का नामकरण यहां परेशानी पैदा कर रहा है। लिंकर अनसुलझे प्रतीकों के बारे में शिकायत कर रहा है। वैसे मैं अपने C प्रोजेक्ट पर C ++ कंपाइलर का उपयोग नहीं कर सकता क्योंकि अन्य सामान बहुत तोड़ता है। रास्ता क्या है?

वैसे मैं MSVC का उपयोग कर रहा हूँ



जब आप C ++ लाइब्रेरी को नियंत्रित करते हैं: stackoverflow.com/questions/12615683/…
Ciro Santilli 病

2
एल

जवाबों:


95

आपको अपने C ++ कोड की कार्यक्षमता को उजागर करने के लिए C API बनाने की आवश्यकता है। मूल रूप से, आपको C ++ कोड लिखने की आवश्यकता होगी जिसे बाहरी "C" घोषित किया गया है और जिसमें एक शुद्ध C API (वर्गों का उपयोग नहीं करना है, उदाहरण के लिए) जो C ++ लाइब्रेरी को लपेटता है। फिर आप अपने द्वारा बनाए गए शुद्ध C रैपर लाइब्रेरी का उपयोग करें।

आपका C API वैकल्पिक रूप से ऑब्जेक्ट-ओरिएंटेड स्टाइल का अनुसरण कर सकता है, भले ही C ऑब्जेक्ट-ओरिएंटेड न हो। उदाहरण के लिए:

 // *.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
पंजे

1
आप अंतिम निष्पादन योग्य कैसे लिंक करते हैं? क्या आप C या C ++ का उपयोग करते हैं? (जब मैंने C का उपयोग किया था, तो लिंकर C ++ फ़ंक्शन को नहीं खोज सका; जब मैंने C ++ का उपयोग किया, तो लिंकर को st :: :: cout नहीं मिला।)
Zack

1
@Zack यदि आप C ++ कंपाइलर / लिंकर के साथ एक स्टैटिक लाइब्रेरी बनाते हैं जिसमें ट्रांज़िटिवली उसकी निर्भरताएँ शामिल हैं (C ++ स्टैण्डर्ड लाइब्रेरी सहित, जो आपके लिंकर द्वारा कथित रूप से लिंक की जा सकती है), आपको उस कोड के साथ स्टैटिक लाइब्रेरी को लिंक करने में सक्षम होना चाहिए। सी संकलक / लिंकर।
माइकल आरोन सफ़यान

क्या आप C ++ से C तक का टेम्पलेट निर्यात कर सकते हैं?
मार्कस जे

मेरे पास एक "हाइब्रिड" व्यवहार है क्योंकि मुझे अपनी लाइब्रेरी को C ++ और C कोड दोनों से बुलाया जाना चाहिए। लिंक समय पर "अपरिभाषित संदर्भ" त्रुटियों से बचने के लिए *.cpp fileमुझे कार्यों को #ifdef _cplusplus+ में लपेटने की भी आवश्यकता थी extern "C"
नारियल

41

मैं इसे निम्नलिखित तरीके से करूंगा:

(यदि MSVC के साथ काम कर रहे हैं, तो GCC संकलन कमांड को अनदेखा करें)

मान लीजिए कि मेरे पास AAA नाम की एक C ++ क्लास है , जिसे aaa.h, aaa.cpp फ़ाइलों में परिभाषित किया गया है , और क्लास AAA में SayHi (const char * name) नाम की एक विधि है , जिसे मैं C कोड के लिए सक्षम करना चाहता हूं।

कक्षा एएए का सी ++ कोड - शुद्ध सी ++, मैं इसे संशोधित नहीं करता हूं:

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;
}

इस कक्षा को नियमित रूप से C ++ के लिए संकलित करना। यह कोड "पता नहीं" है कि यह C कोड द्वारा उपयोग किया जाने वाला है। कमांड का उपयोग करना:

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

अब, C ++ में भी, C कनेक्टर बना रहा है। इसे फाइलों में परिभाषित करना aaa_c_connector.h, aaa_c_connector.cpp । यह कनेक्टर एक फ़ंक्शन को परिभाषित करने जा रहा है, जिसका नाम AAA_sayHi (cosnt char * name) है , जो AAA के एक उदाहरण का उपयोग करेगा और इसकी विधि को कॉल करेगा:

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

एक नियमित C ++ संकलन कमांड का उपयोग करके, इसे फिर से संकलित करना:

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

अब मेरे पास एक साझा पुस्तकालय (libaaa_c_connector.so) है, जो C फ़ंक्शन AAA_sayHi (const char * name) को लागू करता है । मैं अब C मुख्य फ़ाइल बना सकता हूँ और इसे एक साथ संकलित कर सकता हूँ:

main.c

#include "aaa_c_connector.h"

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

    return 0;
}

C संकलन कमांड का उपयोग करके इसे संकलित करना:

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

मुझे $ PWD शामिल करने के लिए LD_LIBRARY_PATH को सेट करने की आवश्यकता होगी, और यदि मैं निष्पादन योग्य ./c_aaa चलाता हूं , तो मुझे वह आउटपुट मिलेगा जिसकी मुझे उम्मीद है:

Hi David
Hi James

संपादित करें:

कुछ लिनक्स वितरण पर, -laaaऔर -lstdc++अंतिम संकलन कमांड के लिए भी आवश्यक हो सकता है। @AlaaM को धन्यवाद। तवज्जो देने के लिए


1
तुम भी साथ lib लिंक पथ निर्दिष्ट कर सकता हैgcc usecpp.c -L. -laaa_c_connector -Wl,-rpath,. -o c_aaa
Metaphox

क्या है usecpp.c?
आल्हा एम।

1
पिछले संकलन लाइन किया जाना चाहिए: gcc main.c -L. -laaa_c_connector -laaa -lstdc++ -o c_aaa। ध्यान दें -laaaऔर-lstdc+++
Alaa M.

@AlaaM। किसी ने मेरा कोड संपादित किया और बदल main.cदिया usecpp.c। मैंने अभी इसे वापस कर दिया है .... अन्य टिप्पणी के बारे में, यह भी उसी तरह काम करना चाहिए। दूसरा संकलन का उपयोग करता है -laaaऔर यह शायद पर्याप्त होना चाहिए (मैं इसे अधिक से अधिक 1.5 साल पहले लिखा था, मैं बहुत अच्छी तरह से मैं क्या किया याद नहीं है, लेकिन मुझे लगता है मैं पोस्टिंग से पहले हर लाइन का परीक्षण किया लगता है)
SomethingSomething

1
ठीक है, इसे पोस्ट के अंत में एक नोट के रूप में जोड़ा गया। ध्यान देने के लिए धन्यवाद!
कुछ

6

यदि आप ऐसा करना चाहते हैं, तो आपको C C में C के लिए एक आवरण लिखना होगा। C ++ पीछे की ओर संगत है, लेकिन C आगे की संगत नहीं है।


5

C ++ API को C- कम्पेटिबल (कोई क्लास, टेम्प्लेट आदि नहीं) मानकर, आप इसे extern "C" { ... }उसी तरह से लपेट सकते हैं , जैसे आपने दूसरे रास्ते पर जाते समय किया था।

यदि आप वस्तुओं और अन्य प्यारा सी ++ सामान को उजागर करना चाहते हैं, तो आपको एक आवरण एपीआई लिखना होगा।


बिल्कुल नहीं ... C ++ लाइब्रेरी को फिर से खोलने की आवश्यकता होगी।
माइकल आरोन सफायन

अरे नहीं। C ++ API पूरी तरह ऑब्जेक्ट-ओरिएंटेड है।
पंजे

2
@क्लाव्स, ओओपी-शैली सी कोड बनाने पर मेरा लेख देखें .. और सी इंटरफेस के साथ उस शैली का उपयोग करके एक आवरण पुस्तकालय बनाएं, लेकिन एक अंतर्निहित सी ++ कार्यान्वयन। फिर C इंटरफ़ेस से लिंक करें।
माइकल आरोन सफायन

आप swig, pyboost, जैसे रैपर 'टूल्स' पर एक नज़र डालना चाहते हैं ... कि बराबर सामान (अभी तक सी की ओर नहीं ...)
xtofl

2

अपने C ++ को एक्सटर्नल "C" (उर्फ C स्टाइल सिंबल) के रूप में एक्सपोर्ट करें, या C ++ लिंकर के लिए अचयनित एक्सपोर्ट सिंबल को परिभाषित करने के लिए .def फाइल फॉर्मेट का उपयोग करें जब वह C ++ लाइब्रेरी बनाता है, तो C लिंकर को इसे पढ़ने में कोई परेशानी नहीं होनी चाहिए।


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;
}

2
कृपया अपने उत्तरों में कुछ स्पष्टीकरण जोड़ें।
HMD

उपरोक्त प्रश्न का उत्तर कैसे दिया जाता है, इसका संक्षिप्त विवरण उत्तर को दूसरों के लिए अधिक उपयोगी बनाता है।
एसओएस

-3

आप बाहरी "C" कीवर्ड के साथ फ़ंक्शन घोषणा को उपसर्ग कर सकते हैं, जैसे

एक्सटर्नल "C" इंट माइसीपफंक्शन ()

{

// यहाँ कोड आता है

वापसी 0;

}

अधिक उदाहरणों के लिए आप Google पर "बाहरी" कीवर्ड के बारे में अधिक खोज कर सकते हैं। आपको कुछ और चीजें करने की आवश्यकता है, लेकिन यह मुश्किल नहीं है कि आपको Google से बहुत सारे उदाहरण मिलेंगे।


तीन डाउनवोट और एक भी स्पष्टीकरण नहीं। हमेशा की तरह महान, एसओ समुदाय।
ज़िमानो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.