2010-02-04 2 views
14

Я пытаюсь получить доступ к классу C++ и вызывать его метод из файла .c.Как вызвать класс C++ и его метод из файла c

Я Google эту тему и найти этот http://developers.sun.com/solaris/articles/mixing.html

Он говорит:

You can write extern "C" functions in C++ that access class M objects and call them from C code.

Вот функция C++ предназначена для вызова функции-члена foo:

extern "C" int call_M_foo(M* m, int i) { return m->foo(i); } 

Мой вопрос где я могу поставить строку? В моем файле C++ .h? Или C .h файл?

И он идет дальше и говорит:

Ниже приведен пример кода C, который использует класс M:

struct M;      // you can supply only an incomplete declaration 

int call_M_foo(struct M*, int); // declare the wrapper function 

int f(struct M* p, int j)  // now you can call M::foo 
{ 
    return call_M_foo(p, j); 
} 

Но как/где я создаю класс M в моем файле C ? И где я могу поставить код выше? C .h файл? C++ .h файл? Или C .c файл?

спасибо.

Благодарим за Подробный ответ GMan. Я выполнил ваше предложение. Но я получаю ошибку компиляции в моем файле .c.

main.c:33:
./some_class.h:24: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘’ token
./some_class.h:25: error: expected ‘)’ before ‘
’ token
./some_class.h:26: error: expected ‘)’ before ‘*’ token

И вот моя some_class.h линия 24-26:

#ifdef __cplusplus 
class M { 

public: 
    M(); 
    virtual ~M(); 

    void method1(char* name, char* msg); 
}; 

extern "C" { 
#else 
struct M; 
#endif 

    /* access functions line 24-26 are here*/ 
    M* M_new(void); 
    void M_delete(M*); 
    void M_method1(M*, char*, char*); 
#ifdef __cplusplus 
} 
#endif 

По какой-то причине, мой C компилятор не нравится extern "C" в GMan «s оригинальный some_test.h. Поэтому я должен изменить это выше. Похоже, компилятор C не любит/понимает линию struct M;.

Любая идея будет высоко оценена.

+0

В то время как я не говорил о extern «C», в этой статье содержится много соответствующей информации о доступе к OO C++ apis с сайта http://stackoverflow.com/questions/2045774/developing-c-wrapper-api -for-object-oriented-c-code/ –

+0

@Peter: Я исправлю материал extern «C». Компилятор C не имеет понятия, что это значит, поэтому мы делаем макрос, который превращается в «extern» C »на C++ и ничего в C. Причина, по которой нам нужен extern« C », заключается в том, что C++ управляет именами при компиляции. C не делает, поэтому, используя 'extern 'C" ', мы даем компилятору знать, чтобы это было скомпилировано« C way ». – GManNickG

ответ

25

Ваш файл заголовка, который является общим между C и C++ код:

#ifdef __cplusplus // only actually define the class if this is C++ 

class some_class 
{ 
    public: 
     int some_method(float); 
}; 

#else 

// C doesn't know about classes, just say it's a struct 
typedef struct some_class some_class; 

#endif 

// access functions 
#ifdef __cplusplus 
    #define EXPORT_C extern "C" 
#else 
    #define EXPORT_C 
#endif 

EXPORT_C some_class* some_class_new(void); 
EXPORT_C void some_class_delete(some_class*); 
EXPORT_C int some_class_some_method(some_class*, float); 

Затем исходный файл:

#include "some_foo.h" 

int some_class::some_method(float f) 
{ 
    return static_cast<int>(f); 
} 

// access functions 
EXPORT_C some_class* some_class_new(void) 
{ 
    return new some_class(); 
} 

EXPORT_C void some_class_delete(some_class* this) 
{ 
    delete this; 
} 

EXPORT_C int some_class_some_method(some_class* this, float f) 
{ 
    return this->some_method(f); 
} 

Теперь компилируем этот источник и ссылку на него. Ваш источник C будет выглядеть примерно так:

#include "some_class.h" 

some_class* myInstance = some_class_new(); 

int i = some_class_some_method(myInstance, 10.0f); 

some_class_delete(myInstance); 

Если вы серьезно относитесь к смешиванию C и C++, вам понадобятся макросы.


Вот некоторые примеры макросов, что бы сделать это гораздо проще:

// in something like c_export.h 
// extern "C" macro 
#ifdef __cplusplus 
    #define EXPORT_C extern "C" 
#else 
    #define EXPORT_C 
#endif 

// new 
#define EXPORT_C_CLASS_NEW(classname) EXPORT_C \ 
      classname * classname##_new(void) 

#define EXPORT_C_CLASS_NEW_DEFINE(classname) \ 
      EXPORT_C_CLASS_NEW(classname) \ 
      { return new classname(); } 

// repeat as much as you want. allows passing parameters to the constructor 
#define EXPORT_C_CLASS_NEW_1(classname, param1) EXPORT_C \ 
      classname * classname##_new(param1 p1) 

#define EXPORT_C_CLASS_NEW_1_DEFINE(classname, param1) \ 
      EXPORT_C_CLASS_NEW_1(classname, param1) \ 
      { return new classname (p1); } 

// delete 
#define EXPORT_C_CLASS_DELETE(classname) EXPORT_C \ 
      void classname##_delete(classname * this) 

#define EXPORT_C_CLASS_DELETE_DEFINE(classname) \ 
      EXPORT_C_CLASS_DELETE(classname) \ 
      { delete this; } 

// functions 
#define EXPORT_C_CLASS_METHOD(classname, methodname, ret) EXPORT_C \ 
      ret classname##_##methodname##(classname * this) 

#define EXPORT_C_CLASS_METHOD_DEFINE(classname, methodname, ret) \ 
      EXPORT_C_CLASS_METHOD(classname, methodname, ret) \ 
      { return this->##methodname##(); } 

// and repeat as necessary. 
#define EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) EXPORT_C \ 
      ret classname##_##methodname(classname * this, param1 p1) 

#define EXPORT_C_CLASS_METHOD_1_DEFINE(classname, methodname, ret, param1) \ 
      EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) \ 
      { return this->##methodname##(p1); } 

И так далее. Наш заголовок/источник становится:

// header 
#include "c_export.h" // utility macros 

#ifdef __cplusplus // only actually define the class if this is C++ 

class some_class 
{ 
    public: 
     int some_method(float); 
}; 

#else 

// C doesn't know about classes, just say it's a struct 
typedef struct some_class some_class; 

#endif 

// access functions 
EXPORT_C_CLASS_NEW(some_class); 
EXPORT_C_CLASS_DELETE(some_class); 
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float); 

// source 
#include "some_foo.h" 

int some_class::some_method(float f) 
{ 
    return static_cast<int>(f); 
} 

// access functions 
EXPORT_C_CLASS_NEW_DEFINE(some_class); 
EXPORT_C_CLASS_DELETE_DEFINE(some_class); 
EXPORT_C_CLASS_METHOD_1_DEFINE(some_class, some_method, int, float); 

И это гораздо более краткий. Его можно было бы упростить (возможно) с помощью переменных макросов, но это нестандартно, и я оставляю это вам. :] Также вы можете сделать макрос для нормальных функций, не являющихся членами.


Обратите внимание, что C делает не знаю, что ссылки. Если вы хотите привязываться к ссылке, лучшим вариантом является, вероятно, просто написать определение экспорта вручную. (Но я подумаю об этом, возможно, мы сможем получить его автоматически).

Представьте, что наш some_class взял float ссылкой (не const) (по любой причине). Мы бы определили такую ​​функцию:

// header 
// pass by pointer!          v 
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*) ; 

// source 
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*) 
{ 
    // dereference pointer; now can be used as reference 
    return this->some_method(*p1); 
} 

И вот мы идем. C будет взаимодействовать со ссылками с указателями вместо:

// c source, if some_method took a reference: 
float f = 10.0f; 
int i = some_class_some_method(myInstance, &f); 

И мы проходим f «по ссылке».

+0

Один nit - ваши функции some_class_construct/destruct следует называть some_class_new/delete вместо этого, поскольку это то, что они делают. Вызов их конструкции/разрушения очень запутанный –

+0

@ Крис: Ну, они * делают * строить и разрушать, но вы правы; это не их главная цель. – GManNickG

+0

@GMan - в C, если вы просто делаете 'struct name', вы не можете ссылаться на него просто как' name'. Чтобы сделать это, вы хотите сделать 'typedef struct name name' –

3

Вам нужно разбить его среди заголовков и файлов C++.

foo.h:

extern "C" int call_M_foo(M* m, int i); 

foo.cc:

extern "C" int call_M_foo(M* m, int i) { 
    return m->foo(i); 
} 

Чтобы создать объект типа M, вы должны были бы аналогичные функции:

foo.h:

struct M; 
extern "C" M* create_M(); 

foo.куб.см:

extern "C" M* create_M() { 
    return new M; 
} 
0

На сайте вы связаны есть ответ уже:

You can declare function print in a header file that is shared by C and C++ code:

#ifdef __cplusplus extern "C" 
#endif int print(int i, double d); 

You can declare at most one function of an overloaded set as extern "C" Here is the example C header for the wrapper functions:

int g_int(int); 
double g_double(double); 

В принципе, может быть заголовок разделяется между двумя, которые декларирует , добавив модификатор extern «C», если вы находитесь на C++, чтобы обеспечить доступ к функции в объекте из C. Вы определяете тело функционала n позже в коде C++, как обычно, при необходимости внутри класса и т. д., и вы используете функцию в C, как обычно.

2

У вас здесь есть несколько вопросов, поэтому я отвечу на них отдельно.

My question is where do I put the about line? In my c++ .h file? or c .h file?

extern "C" линия идет в файле C++.По сути, он говорит компилятору, что ограничивает все блоки extern "C" подмножеством C на C++ и соответственно.

But how/where do I create the class M in my c file?

Вы не можете. C не имеет понятия классов, и нет абсолютно никакого способа создать экземпляр класса напрямую. Вам необходимо экспортировать функцию C в ваш файл C++, который создает класс и возвращает его как указатель. Затем вы получите этот указатель вокруг вашего приложения C. Фактически вы не можете изменять класс непосредственно в своем приложении C, потому что C не поддерживает классы, а ваш компилятор C++ может вставлять «скрытые» переменные для ведения бухгалтерского учета внутри фактического объявления класса .

And where do I put the above code?

Кусок кода, который использует указатель на struct URE идет в файле C. Вы используете , чтобы использовать указатель struct, поскольку C не поддерживает классы вообще. Вы можете поместить вызовы функций, используя эту функцию в любом месте C-реализации , как и обычные вызовы функций C.

1

Вся необходимая информация находится в той ссылке, которую вы предоставляете. Вам просто нужно понять, что необходимо строгое разделение между кодом C и C++.

  1. Код C++ может называть любой код C.
  2. C код обычно не может вызывать любой код на C++.
  3. Функции C могут быть реализованы кодом C++.

Ключевая часть, чтобы понять, что компиляторы С и С ++ искажать имена функций при создании объектных файлов по-разному, поэтому они, как правило, не в состоянии взаимодействовать (во время связи), за исключением того, что C++ может запрошен знать разницу с помощью extern "C"

прототип: void f(int); может быть искусал C компилятором: _f, но компилятор C++ может выбрать совсем другое имя, например, f_int, и поэтому компоновщик не знал бы, что они, как предполагается, быть одинаковым.

Однако:

extern "C" void f(int);

будут подогнаны компилятором C++, чтобы _f, но компилятор Си бы дроссель на extern "C". Чтобы избежать этого, вы должны использоваться что-то вроде этого:

#ifdef __cplusplus 
extern "C" { 
#endif 

void f(int); 

#ifdef __cplusplus 
} /* closing brace for extern "C" */ 
#endif 

Теперь все выше раздела может жить в файл .h и, как sun.com состояний статьи, заголовок смешанного языка.

Это означает, что .c или .cpp файл может #include этот заголовок и код можно назвать f();
и либо .c или.CPP файл может #include этот заголовок и реализовать его:

void f() 
{ 
} 

Теперь хороший бит, что .cpp файл может реализовать эту функцию, чтобы вызвать любой код С ++ это нравится.

Теперь, чтобы ответить на ваши конкретные вопросы:

  1. Первый пример кода может идти только в файле .cpp.
  2. Второй пример кода может входить только в .c файл.

Кроме того, класс M должен быть объявлен и определен только в файлах на C++.

Смежные вопросы