Wywołanie funkcji C z kodu C++

Mam funkcję C, którą chciałbym wywołać z C++. Nie mogłem użyć podejścia " extern "C" void foo()", ponieważ funkcja C nie została skompilowana przy użyciu g++. Ale kompiluje dobrze za pomocą gcc. Jakieś pomysły jak wywołać funkcję z C++?

Author: Jonathan Leffler, 2013-05-31

4 answers

Skompiluj kod C tak:

gcc -c -o somecode.o somecode.c

Następnie kod C++ w następujący sposób:

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

Następnie połącz je razem, za pomocą linkera C++:

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

Musisz również powiedzieć kompilatorowi C++, że nagłówek C nadchodzi, gdy dołączysz deklarację dla funkcji C. Więc othercode.cpp zaczyna się od:

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

somecode.hpowinno zawierać coś w rodzaju:

 #ifndef SOMECODE_H_
 #define SOMECODE_H_

 void foo();

 #endif


(użyłem gcc w tym przykładzie, ale zasada jest taka sama dla każdego kompilatora. Budować osobno jako C i C++, a następnie połączyć je ze sobą.)
 92
Author: Prof. Falken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-23 12:03:29

Pozwól, że zbiorę fragmenty z innych odpowiedzi i komentarzy, aby dać ci przykład z czystym kodem C i C++:

Część C:

Foo.h :

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif 

Foo.c

#include "foo.h"

void foo(void)
{
    /* ... */
}

Skompiluj to za pomocą gcc -c -o foo.o foo.c.

Część C++:

Bar.cpp

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

void bar() {
  foo();
}

Skompiluj to z g++ -c -o bar.o bar.cpp

A następnie połączyć to wszystko razem:

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

Uzasadnienie: Kod C powinien być zwykłym kodem C, Nie #ifdefs jak "może kiedyś nazwę To z innego języka". Jeśli jakiś Programista C++ wywoła twoje funkcje C, to jest ich problem JAK to ZROBIĆ, NIE Twój. A jeśli jesteś programistą C++, to nagłówek C może nie być twój i nie powinieneś go zmieniać, więc obsługa niezmieszanych nazw funkcji (np. extern "C") należy do Twojego kodu C++.

Możesz oczywiście napisać sobie wygodny nagłówek C++, który nie robi nic poza owijaniem nagłówka C w extern "C" deklaracja.

 42
Author: Arne Mertz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 04:11:18

Zgadzam się z odpowiedzią Prof. Falkena , ale po komentarzu Arne ' a Mertza chcę podać pełny przykład (najważniejsza część to #ifdef __cplusplus):

Jakiś kod.h

#ifndef H_SOMECODE
#define H_SOMECODE

#ifdef __cplusplus
extern "C" {
#endif

void foo(void);

#ifdef __cplusplus
}
#endif

#endif /* H_SOMECODE */

Jakiś kod.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
    // ...
}

Następnie postępuj zgodnie z instrukcjami Prof. Falkena, aby skompilować i połączyć.

To działa, ponieważ podczas kompilacji z gcc, makro __cplusplus nie jest zdefiniowany, więc nagłówek somecode.h zawarty w somecode.c jest taki po wstępnym przetworzeniu:

void foo(void);

I przy kompilacji z g++, wtedy __cplusplus jest zdefiniowany, a więc nagłówek zawarty w othercode.cpp jest teraz taki:

extern "C" {

void foo(void);

}
 16
Author: gx_,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:44

Ta odpowiedź jest inspirowana przypadkiem, w którym uzasadnienie Arne ' a było poprawne. Jednak najnowsza wersja wspierała tylko C. następujące dyrektywy pozostawione w kodzie były mylące: {]}

#ifdef __cplusplus
extern "C" {
#endif

To kosztowało mnie kilka godzin próby kompilacji w C++. Proste wywołanie C z C++ było znacznie łatwiejsze.

Konwencja ifdef __cplusplus narusza zasadę jednej odpowiedzialności. Kod wykorzystujący ten Konwent próbuje robić dwie rzeczy na raz:

  • (1) Wykonaj funkcję w C -- i --
  • (2) wykonanie tej samej funkcji w C++
To tak, jakby próbować pisać zarówno po amerykańsku, jak i po Brytyjsku w tym samym czasie. To niepotrzebnie wrzuca # ifdef _ _ thequeensenglish spanner #elif _ _ yankeenglish wrench # else bezużyteczne narzędzie, które utrudnia odczytanie kodu # endif w kodzie.

Dla prostego kodu i małych bibliotek ifdef _Konwencja _cplusplus może działać, jednak w przypadku złożonych bibliotek najlepiej wybrać jeden lub drugi język i trzymać się go. Obsługa jednego z języków wymaga mniej konserwacji niż próba obsługi obu języków.

Jest to zapis modyfikacji, które zrobiłem w kodzie Arne ' a, aby go skompilować na 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
Author: Agriculturist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-22 03:21:13