2015-03-11 9 views
1

Folks Предполагая, у меня есть C++ приложение/библиотека работает, реализующий сказатьВызов кода приложения C++ из библиотеки C?

/* Alloc API */ 
void* my_alloc(int size) { 
    return malloc(sizeof(size)); 
} 

Это не под "экстерном с".

У меня есть динамическая библиотека C, из которой мне нужно позвонить my_alloc, могу ли я напрямую вызвать этот API?

Like, 

int test_my_alloc (int size) { 
    int *x; 

    x = (int*)my_alloc(size); 
    if (x == NULL) { 
     return 0; 
    } else { 
     return 1; 
    } 
} 
+4

Возможно, вы захотели 'malloc (size);' вместо 'malloc (sizeof (size));'. Но вы столкнетесь с проблемами, так как вам действительно нужно 'malloc (size * sizeof (int));' –

+0

Nope - вам нужно объявить 'my_alloc' как' extern 'C "или реализовать оболочку в вашей библиотеке C++, которая делает это. –

+0

@CoolGuy, который был типом, забудьте об этом, я смотрю, как вызвать my_alloc из библиотеки C. – Madhava

ответ

8

Вам необходимо создать заглушку, например.

Заглушка Заголовок:

// stub.h 

#ifdef __cplusplus 
extern "C" { 
#endif 

void* my_alloc_c(int size); 

#ifdef __cplusplus 
} 
#endif 

реализация Заглушка:

// stub.cpp 

#include "stub.h" 
#include "header_where_my_alloc_is_declared.h" 

void* my_alloc_c(int size) 
{ 
    return my_alloc(size); 
} 

Ваш C-код (пример):

// my_code.c 

#include "stub.h" 

int main() 
{ 
    void * p = my_alloc_c(42); 
    return 0; 
} 

Затем скомпилировать окурок и связать его с вашим кодом C:

g++ -Wall -c stub.cpp   # compile stub.cpp 
gcc -Wall my_code.c stub.o  # compile your C code and link with stub.o 
+0

Об этом думали, но, к сожалению, это включает в себя более 100 API-оболочек, для которых мы должны написать библиотеку, поэтому это считалось последним подходом, если мы не нашли другого решения. Во всяком случае, похоже, что ничего не может быть сделано иначе, чем API-интерфейсы обертки. – Madhava

+0

ОК - опять же, эта информация должна была быть в вопросе - если вы не приложите усилий, чтобы объяснить всю проблему, то это походит на вытягивание зубов для тех, кто пытается предоставить решение. –

+1

Согласен, извините за неясность. – Madhava

5

Как Paul R. answered, вам нужен код-заглушка. Кроме того, вы лучше убедитесь, что ваша функция C++ не выбрасывает exceptions (я полагаю, что функция C++, вызываемая из программы C и main, которая генерирует неперехваченное исключение, имеет undefined behavior). BTW, вы должны быть уверены, что конструктор данных static C++ (например, std::cout) называется «концептуально» перед вашим main в C (так что вам лучше связать свою программу с компилятором C++, а не с C). См GCC __attribute__(constructor)

В практике, по крайней мере, на Linux с C++ кода, составленный GCC (g++) или Clang/LLVM (clang++), функция C++ имеет некоторые mangled name.

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

int main(int argc, char**argv) { 
    extern void* _Z10my_alloc_ci(int size); 
    void * p = _Z10my_alloc_ci(42); 
    return 0; 
} 

, но я немного стыжусь давать такие глупые советы. Вы даже можете использовать asm labels, например.

extern void*f(int) asm ("_Z10my_alloc_ci"); 
p = f(42); 

Однако, я чувствую, что вы не должны иметь никаких таких подходов, и я удивлен, почему вам нужно вызвать функцию C++, которая не обернута вокруг extern "C". Обратите внимание: теоретически функции C++ (без extern "C") могут иметь и другие - и несовместимые - calling convention, чем функции C. Я не знаю, как это делается.Таким образом, чтобы быть в безопасности, вы должны обернуть функцию C++ с некоторыми C++ обертывания с использованием extern "C"

Чтобы избежать пойманных исключений, вы можете поймать их все в вашем C++ обертка:

#include <cstdio> 
#include <cstdlib> 
extern "C" void* my_alloc_c(int size) { 
    extern void* my_alloc(int); 
    try { 
    return my_alloc(size); 
    } catch (...) { 
    ::fprintf(::stderr, "got uncaught C++ exception for my_alloc(%d)\n", 
      size); 
    ::fflush(nullptr); 
    ::abort(); 
    } 
} 

BTW, если C++ библиотеки Возможно, вы попытаетесь автоматизировать генерацию кода клея. Например, вы можете настроить GCC, используя MELT (язык, подходящий для конкретного языка Lispy для расширения GCC), путем кодирования расширения в MELT, которое сгенерировало бы код при компиляции файлов заголовков C++.

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

1

Из того, что я собрал:

  1. У вас есть C++ библиотека не имеют никакого контроля над (вы не можете добавить Экстерн «C»)
  2. У вас есть библиотека C, которая должна вызывать с ++ библиотека
  3. вы можете изменить вашу библиотеку C, чтобы приспособить решение (вы можете изменить Makefile и изменить название функции, которую вы хотите позвонить)

Итак, одним из альтернативных решений было бы скомпилировать вашу библиотеку C с помощью того же C++-компилятора, который используется для этой библиотеки C++, если это приемлемо для вас.

Примечание: с C89, вам, возможно, потребуется изменить биты кода (например, недействительным * Т * преобразования не неявное больше в C++ ), но это, вероятно, будет легче, чем 100+ оберток ,

Примечание 2: Если вы используете некоторые функции C99 (, например, в Власе ), то этот код не будет компилироваться в C++.

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