Вызов функции C из кода C ++

У меня есть функция C, которую я хотел бы вызвать из C ++. Я не мог использоватьextern "C" void foo()«такой подход, потому что не удалось скомпилировать функцию C с использованием g ++. Но она прекрасно компилируется с использованием gcc. Есть идеи, как вызвать функцию из C ++?

68

Решение

Скомпилируйте код C следующим образом:

gcc -c -o somecode.o somecode.c

Тогда код на C ++ выглядит так:

g++ -c -o othercode.o othercode.cpp

Затем свяжите их вместе с помощью компоновщика C ++:

g++ -o yourprogram somecode.o othercode.o

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

extern "C" {
#include "somecode.h"}

somecode.hдолжен содержать что-то вроде:

 #ifndef SOMECODE_H_
#define SOMECODE_H_

void foo();

#endif

(Я использовал gcc в этом примере, но принцип тот же для любого компилятора. Соберите отдельно как C и C ++ соответственно, затем соедините его вместе.)

99

Другие решения

Позвольте мне собрать кусочки из других ответов и комментариев, чтобы привести пример с четко разделенным кодом C и C ++:

foo.h:

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif

foo.c

#include "foo.h"
void foo(void)
{
/* ... */
}

Скомпилируйте это с gcc -c -o foo.o foo.c,

bar.cpp

extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"}

void bar() {
foo();
}

Скомпилируйте это с g++ -c -o bar.o bar.cpp

А затем связать все это вместе:

g++ -o myfoobar foo.o bar.o

Обоснование:
Код C должен быть простым кодом C, нет #ifdefs для «может быть, когда-нибудь я позвоню это с другого языка». Если какой-то программист C ++ вызывает ваши функции на C, это их проблема как это сделать, а не твоя. И если вы программист на C ++, то заголовок C может не принадлежать вам, и вам не следует его менять, так что обработка неискаженных имен функций (т.е. extern "C") принадлежит вашему C ++ коду.

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

48

я согласен с Ответ профессора Фалькена, но после комментария Арне Мерца я хочу привести полный пример (самая важная часть #ifdef __cplusplus):

somecode.h

#ifndef H_SOMECODE
#define H_SOMECODE

#ifdef __cplusplus
extern "C" {
#endif

void foo(void);

#ifdef __cplusplus
}
#endif

#endif /* H_SOMECODE */

somecode.c

#include "somecode.h"
void foo(void)
{
/* ... */
}

othercode.hpp

#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE

void bar();

#endif /* HPP_OTHERCODE */

othercode.cpp

#include "othercode.hpp"#include "somecode.h"
void bar()
{
foo(); // call C function
// ...
}

Затем следуйте инструкциям профессора Фалькена, чтобы скомпилировать и связать.

Это работает, потому что при компиляции с gccмакрос __cplusplus не определено, поэтому заголовок somecode.h включен в somecode.c это как после предварительной обработки:

void foo(void);

и при компиляции с g++, затем __cplusplus является определяется, и поэтому заголовок включен в othercode.cpp теперь так:

extern "C" {

void foo(void);

}
17

Этот ответ вдохновлен случаем, когда обоснование Арне было правильным. Поставщик написал библиотеку, которая когда-то поддерживала как C, так и C ++; однако последняя версия поддерживала только C. Следующие рудиментарные директивы, оставленные в коде, вводили в заблуждение:

#ifdef __cplusplus
extern "C" {
#endif

Это стоило мне нескольких часов, пытаясь скомпилировать в C ++. Просто вызвать C из C ++ было намного проще.

Соглашение ifdef __cplusplus нарушает принцип единой ответственности. Код, использующий это соглашение, пытается сделать две вещи одновременно:

  • (1) выполнить функцию в C
    — а также —
  • (2) выполнить ту же функцию в C ++

Это все равно что пытаться писать на американском и британском английском одновременно. Это излишне выбрасывает #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else бесполезный инструмент, который затрудняет чтение кода #endif в коде.

Для простого кода и небольших библиотек может работать соглашение ifdef __cplusplus; однако для сложных библиотек лучше выбрать один или другой язык и придерживаться его. Поддержка одного из языков потребует меньшего количества обслуживания, чем попытка поддержать оба.

Это запись изменений, которые я сделал в коде Арне, чтобы он компилировался в Ubuntu Linux.

foo.h:

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif

foo.c

#include "foo.h"#include <stdio.h>

void foo(void)
{
// modified to verify the code was called
printf("This Hello World was called in C++ and written in C\n");
}

bar.cpp

extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"}

int main() {
foo();
return(0);
}

Makefile

# -*- MakeFile -*-
# dont forget to use tabs, not spaces for indents
# to use simple copy this file in the same directory and type 'make'

myfoobar: bar.o foo.o
g++ -o myfoobar foo.o bar.o

bar.o: bar.cpp
g++ -c -o bar.o bar.cpp

foo.o: foo.c
gcc -c -o foo.o foo.c
0
По вопросам рекламы [email protected]