2010-07-07 2 views
6

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

Теперь я хотел бы назвать некоторый код на C++ (я не против изменять код C++, чтобы они вызывались кодом C).

class Utils { 
public: 
    static void fun(); 
} 

class Utils2 { 
public: 
    static std::wstring fun(); 
} 

Если я склонен называть их со следующим синтаксисом, они не будут скомпилированы (я использую VC++ 2008, с кодом C файлы с расширением .c)

Utils::fun(); 
// Opps. How I can access std::wstring in C? 
Utils2::fun(); 

Любое предложение?

+0

Вы явно не сможете вызвать функцию, возвращающую std :: string (или используя std :: string в качестве параметра) из C. –

+0

@tomekszpakowicz: Не сразу, конечно. Но это, безусловно, выполнимо. См. [Мой ответ] (http://stackoverflow.com/questions/3193020/calling-c-static-member-functions-from-c-code/3193099#3193099). – sbi

+0

Еще сложнее: методы членов. –

ответ

7
// c_header.h 
#if defined(__cplusplus) 
extern "C" { 
#endif 

void Utils_func(); 
size_t Utils2_func(wchar_t* data, size_t size); 

#if defined(__cplusplus) 
} 
#endif 
//eof 

// c_impl.cpp 
// Beware, brain-compiled code ahead! 
void Utils_func() 
{ 
    Utils::func(); 
} 

size_t Utils2_func(wchar_t* data, size_t size) 
{ 
    std::wstring wstr = Utsls2::func(); 
    if(wstr.size() >= size) return wstr.size(); 
    std::copy(wstr.begin(), wstr.end(), data); 
    data[wstr.size()] = 0; 
    return str.size(); 
} 
//eof 
+0

Итак, вызывающий C отвечает за выделение/освобождение памяти для данных wchar_t? –

+2

Так я и сделал бы это. Подобный стиль выделения вызывающего абонента очень распространен в библиотеках C. –

+0

@ Ян: Да, это, как правило, самый безопасный. Распределение ресурсов в одной DLL и их освобождение в другом часто создает проблемы. Кроме того, возникают вопросы владения ресурсом. – sbi

-3

C является подмножеством C++ .. Так и может не позвонить с членами ++ классов и пространств имен в С.

+0

-1 ясно, что об этом читатель понимает - таким образом, вопрос – Elemental

1

Я думаю, что единственное решение, чтобы обернуть их в стиле C глобальных функций в коде C++, как:

extern "C" int Util2_Fun() { return Util2::Fun(); } 

Я полагаю, вы могли бы также объявить глобальные указатели на функции, как экстернов, используя некоторые неприятные изменения:

extern int (*Utils2_Fun)()=(int *())(Util2::Fun); 

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

+2

, который должен быть extern «C» в первом примере, или он будет подвержен namemangling. – falstro

+0

Спасибо, отредактированный как таковой, моя ошибка. – Elemental

5

насчет обертки

extern "C" void Utilsfun(int i){Utils::fun(i);} 

Update:

То есть, как вы можете вызвать функции C++ из C, но доступ к станд :: wstring из C другое дело.

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

extern "C" 
{ 
void * ObjectCreate(){return (void *) new Object();} 
void ObjectOperate(void *object, char *parameter){((Object*)object)->Operate(parameter);} 
void ObjectDelete(void *object){delete ((Object*)object);} 
} 

Вы должны быть очень осторожными, об управлении созданием и стирания.

+1

Как насчет std :: wstring handling? –

+0

extern "C" wchar_t const * Utilsfun (int i) {... –

+0

@Chris: А кто выделяет/удаляет буфер символов и как? Гораздо лучше писать в буфер-вызывающий. См. [Мой ответ] (http://stackoverflow.com/questions/3193020/calling-c-static-member-functions-from-c-code/3193099#3193099). – sbi

0

Вы можете сделать C++ вызываемым из C с помощью конструкции extern "C".

0

Наиболее распространенное решение - написать интерфейс C для ваших функций на C++. Это код C++, который объявлен с использованием extern "C" { ... }. Эти функции-обертки могут вызывать любой код на C++, который им нравится, но поскольку они объявлены extern "C", они не будут подвергаться манипуляции именами (вы не можете создавать пространства имен или перегружать здесь).

Это должно быть связано с вашим C-файлом, и вам хорошо идти.

То есть, файл заголовка содержит

#ifdef __cplusplus 
extern "C" { 
#endif 

    void wrapper1(void); 
    int wrapper2(int x); 
    char* wrapper3(int y); 

#ifdef __cplusplus 
} 
#endif 

В ifdefs требуется, чтобы оградить компилятор Си от extern "C". И вы реализуете те, в вашем C источник ++

void wrapper1(void) { Util::funcOne(); } 
int wrapper2(int x) { return Util::funcTwo(x); } 
char* wrapper3(int y) { return Util::funcThree(y); } 
1

Создать функцию-оболочку в вашем C++ код:

extern "C" void Wrapper() { 
    Utils2::fun(); 
} 

, а затем в коде C:

extern void Wrapper(); 
int main() { 
    Wrapper(); 
    return 0; 
} 
0

Если вы делаете, как ppl сказать здесь (используя extern «C») остерегайтесь того, что вы передаете объекты только функции C, которые будут компилироваться в C.

0

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

0

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

0

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

Конечно, если вам нужно, чтобы он оставался компилируемым в C по другим причинам, это не относится.