У меня есть функция C, которую я бы хотел вызвать из С++. Я не мог использовать подход "extern "C" void foo()
", потому что функция C не была скомпилирована с использованием g++. Но он компилируется с использованием gcc. Любые идеи о том, как вызвать функцию из С++?
Вызвать функцию C из кода С++
Ответ 1
Скомпилируйте код 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++, соответственно, затем свяжите его вместе.)
Ответ 2
Позвольте мне собрать кусочки из других ответов и комментариев, чтобы привести пример с четко разделенным кодом C и 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
Часть 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-кодом, без #ifdef
для "возможно, когда-нибудь я позвоню с другого языка". Если какой-то программист C++ вызывает ваши функции на C, это их проблема, а не ваша. И если вы программист C++, то заголовок C может не принадлежать вам, и вам не следует его менять, поэтому обработка неупорядоченных имен функций (т.е. Extern extern "C"
) входит в ваш код C++.
Вы, конечно, могли бы написать себе удобный заголовок C++, который ничего не делает, кроме как оборачивает заголовок C во extern "C"
.
Ответ 3
Я согласен с Проф. Falken answer, но после комментария Арне Мерца я хочу привести полный пример (самая важная часть - #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);
}
Ответ 4
Этот ответ вдохновлен случаем, когда обоснование Арне было правильным. Продавец написал библиотеку, которая когда-то поддерживала и 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; однако для сложных библиотек лучше выбрать один или другой язык и придерживаться его. Поддержка одного из языков потребует меньшего количества обслуживания, чем попытка поддержать оба.
Это запись изменений, которые я сделал в коде Arne, чтобы компилировать его в 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