2013-05-31 2 views
61

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

+0

Не могли бы вы написать несколько примеров коды и '' г ++ сообщения об ошибках –

+0

@MarkGarcia C и C++ являются разными языками. Да, в C есть вещи, которых нет в C++. Мне надоело объяснять это, поэтому я спросил [Почему я не должен компилировать код C с помощью компилятора C++ или писать код на C++ для компиляции в C?] (Http://stackoverflow.com/questions/16247969/ why-shouldnt-i-compile-c-code-with-ac-or-write-c-code-to-be-compileable-in) – Sebivor

+0

Это может быть обратное. _failed для компиляции с использованием gcc. Но он компилируется отлично, используя g ++ _... из-за 'extern 'C'' –

ответ

81

Скомпилировать C так:

gcc -c -o somecode.o somecode.c 

Тогда код C++, как это:

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

Затем связать их вместе с С ++ линкера:

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

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

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

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

#ifndef SOMECODE_H_ 
#define SOMECODE_H_ 

void foo(); 

#endif 


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

+5

Я не хочу использовать nipick, но этот последний код - это * Объявление *, а не * определение *. Однако, поскольку 'somecode.h', возможно, будет заголовком C, который он мог бы использовать и в компиляции C, запись' extern 'C "' в заголовке нарушила бы компиляцию C.Вместо этого он должен обернуть «extern» C «вокруг C-заголовка include в исходный файл C++. –

+6

@ Арне Хорошие очки. Некоторые люди просматривают некоторые C++ в своих C, завершая 'extern 'C" 'в заголовке с помощью [' #ifdef __cplusplus'] (http://stackoverflow.com/questions/3789340/combining-c-and-c-how -does-IFDEF-cplusplus работа). – unwind

+0

@ Арне См. Мой ответ ниже. расслабьтесь Как видите, я один из них;) –

16

Я согласен с Prof. Falken's answer, но после комментария Арне Мерца я хочу gi ве полный пример (наиболее важной частью является #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 
    // ... 
} 

Тогда вы будете следовать инструкции профессора Falken для компиляции и компоновки.

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

void foo(void); 

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

extern "C" { 

void foo(void); 

} 
+1

thb, мне не нравится '#ifdef __cplusplus' в коде C. Код C - это более низкий уровень, и ему не нужно беспокоиться о том, может ли он когда-нибудь вызываться из кода на C++. Imo, что '# ifdef' используется только в коде C++, если вы хотите предоставить заголовок связывания C для библиотеки, написанной на C++, а не наоборот. –

+0

@ArneMertz, тем не менее, это хорошее определение, о котором нужно знать. –

+0

@ Prof.Falken, конечно, но это определение, предназначенное для обеспечения «нисходящей» совместимости кода C++, а не кода C. –

38

Позвольте мне собрать биты и куски из других ответов и комментариев, чтобы дать вам пример с чисто отделенной 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 s для «возможно, когда-нибудь я позвоню на другом языке». Если какой-либо программист на C++ называет ваши функции C, то его проблема, как это сделать, а не ваша. И если вы программист на C++, то заголовок C может не быть вашим, и вы не должны его изменять, поэтому обработка неподключенных имен функций (то есть extern "C") принадлежит вашему коду C++.

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

+3

Кажется законным. +1 для обоснования –

+0

Большое спасибо, это сработало отлично! – Dangila

+0

+1 для обоснования тоже –

0

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

#ifdef __cplusplus 
extern "C" { 
#endif 

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

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

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

Это как попытка написать как на американском, так и на британском английском языке одновременно. Это излишне бросает #ifdef __thequeensenglish гаечный ключ #elif __yankeeengrench гаечный ключ #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 
Смежные вопросы