У меня есть функция C, которую я хотел бы вызвать из C ++. Я не мог использовать " extern "C" void foo()
" подход, потому что функция C не могла быть скомпилирована с использованием g ++. Но он отлично компилируется с использованием gcc. Есть идеи, как вызвать функцию из C ++?
93
g++
сообщений об ошибкахvoid valid_in_C_but_not_in_CPlusPlus(size_t size) { char variable_length_array[size]; }
void f(void *pv) { int *pi = pv; *pi = 42; }
^^Ответы:
Скомпилируйте код 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 ++ соответственно, а затем связывайте их вместе.)
источник
extern "C"
в заголовок с#ifdef __cplusplus
.Позвольте мне собрать отрывки из других ответов и комментариев, чтобы дать вам пример с четко разделенным кодом 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 "C"
) Принадлежит вашему коду C ++.Вы, конечно, можете написать себе удобный заголовок C ++, который ничего не делает, кроме обертывания заголовка C в
extern "C"
объявлении.источник
Я согласен с ответом профессора Фалькена , но после комментария Арне Мертца я хочу привести полный пример (самая важная часть - это
#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); }
источник
#ifdef __cplusplus
код на C. Код C - это нижний уровень, и ему не нужно беспокоиться, если он когда-нибудь будет вызван из кода C ++. Imo,#ifdef
который используется только в коде C ++, если вы хотите предоставить заголовок привязки C для библиотеки, написанной на C ++, а не наоборот.Этот ответ навеян случаем, когда аргументация Арне была правильной. Поставщик написал библиотеку, которая когда-то поддерживала как C, так и C ++; однако последняя версия поддерживала только C. Следующие рудиментарные директивы, оставленные в коде, вводили в заблуждение:
#ifdef __cplusplus extern "C" { #endif
Это стоило мне нескольких часов, пытаясь скомпилировать на C ++. Просто вызвать C из C ++ было намного проще.
Соглашение ifdef __cplusplus нарушает принцип единой ответственности. Код, использующий это соглашение, пытается делать две вещи одновременно:
Это все равно, что пытаться писать одновременно на американском и британском английском. Это излишне бросает #ifdef __thequeensenglish гаечный ключ #elif __yankeeenglish wrench # еще один бесполезный инструмент, который затрудняет чтение кода #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
источник