C ++ kodundan bir C işlevi çağırın


93

C ++ 'dan çağırmak istediğim bir C fonksiyonum var. extern "C" void foo()C işlevi g ++ kullanılarak derlenemediği için " " yaklaşımı kullanamadım. Ama gcc kullanarak iyi derler. C ++ 'dan işlevi nasıl çağıracağınıza dair bir fikriniz var mı?


1
Lütfen bir kaç örnek kod ve g++hata mesajları yazabilir misiniz
Matthieu Rouget

7
Bir C ++ derleyicisiyle derlerseniz, bu C ++ 'dır. C kodunun bir C ++ derleyicisi ile derlenmesi gerekmez. Farklı dillerdir. Kodunuz geçerli C ++ değil ve bu nedenle bir C ++ derleyicisi ile derlenmiyor.
xaxxon

3
@MatthieuRougetvoid valid_in_C_but_not_in_CPlusPlus(size_t size) { char variable_length_array[size]; }
otistik

2
Benim denemem: void f(void *pv) { int *pi = pv; *pi = 42; }^^
gx_

1
Bu, özellikle C (C ++ yerine) derleyicisinin C kodu için nasıl kullanılabileceğini gösteren iyi yanıtlara sahip olduğu için açık bırakılmalıdır.
Chris Stratton

Yanıtlar:


130

C kodunu şu şekilde derleyin:

gcc -c -o somecode.o somecode.c

Sonra C ++ kodu şöyle:

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

Ardından bunları C ++ bağlayıcıyla birbirine bağlayın:

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

Ayrıca C ++ derleyicisine, C işlevi için bildirimi eklediğinizde bir C başlığının geldiğini söylemeniz gerekir. Yani othercode.cppşununla başlar:

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

somecode.h şunun gibi bir şey içermelidir:

 #ifndef SOMECODE_H_
 #define SOMECODE_H_

 void foo();

 #endif


(Bu örnekte gcc kullandım, ancak ilke herhangi bir derleyici için aynıdır. Sırasıyla C ve C ++ olarak ayrı ayrı derleyin ve ardından bunları birbirine bağlayın.)


7
@Arne İyi puanlar. Bazı insanlar extern "C", başlığı ile sararak C'lerinde biraz C ++ schmear #ifdef __cplusplus.
gevşeyin

@Arne Aşağıdaki cevabıma bakın. gevşeyin Gördüğünüz gibi ben onlardan biriyim;)
gx_

1
Çok teşekkür ederim ! Bu benim için çok faydalı oldu :)
Hesham Eraqi

Aşağıdaki hatayı alıyordum: Hata: # 337: bağlantı belirtimi önceki "foo" ile uyumsuz (1. satırda bildirildi) Şimdi derlemesi tamam. Biri açıklayabilir mi?
FaizanHussainRabbani

@FaizanRabbani, daha fazla ayrıntı olmadan olmaz.
Prof. Falken

63

Size net bir şekilde ayrılmış C ve C ++ koduna sahip bir örnek vermek için diğer yanıtlardan ve yorumlardan parçaları bir araya getirmeme izin verin:

C Bölümü:

foo.h :

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif 

foo.c

#include "foo.h"

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

Bunu ile derleyin gcc -c -o foo.o foo.c.

C ++ Bölümü:

bar.cpp

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

void bar() {
  foo();
}

Bunu şununla derleyin: g++ -c -o bar.o bar.cpp

Ve sonra hepsini birbirine bağlayın:

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

Gerekçe: C kodu düz C kodu olmalı, #ifdef"belki bir gün bunu başka bir dilden arayacağım" için s yok . Bazı C ++ programcıları C işlevlerinizi çağırırsa, bunun nasıl yapılacağı sizin değil, onların sorunu. Ve eğer C ++ programcısıysanız, o zaman C başlığı sizin olmayabilir ve onu değiştirmemelisiniz, bu nedenle yönetilmeyen işlev adlarının (yani extern "C") işlenmesi C ++ kodunuza aittir.

Elbette, kendinize C başlığını bir extern "C"bildirime sarmaktan başka hiçbir şey yapmayan kullanışlı bir C ++ başlığı yazabilirsiniz .


8
Mantıklı gibi. Mantık için +1
gx_

Sonunda bunun tamamen açık bir açıklaması. Çok teşekkürler!
Daniel Soutar

16

Prof. Falken'in cevabına katılıyorum ama Arne Mertz'in yorumundan sonra tam bir örnek vermek istiyorum (en önemli kısım şu ki #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
    // ...
}

Ardından Prof. Falken'in derleme ve bağlantı kurma talimatlarını takip edersiniz.

Bu işe yarar, çünkü ile derleme yapılırken gccmakro __cplusplustanımlanmaz, bu nedenle somecode.hdahil edilen başlık somecode.cönişlemeden sonra şu şekildedir:

void foo(void);

ve ile derleme yapılırken g++, o __cplusplus zaman tanımlanır ve böylece othercode.cpp, şimdi dahil edilen başlık şu şekildedir:

extern "C" {

void foo(void);

}

4
thb, #ifdef __cplusplusC kodunu beğenmedim . C kodu alt seviyedir ve bir gün C ++ kodundan çağrılabilirse rahatsız edilmemelidir. #ifdefC ++ ile yazılmış bir kitaplık için bir C bağlama başlığı sağlamak istiyorsanız, yalnızca C ++ kodunda kullanımı olan Imo, tersi değil.
Arne Mertz

2
@ Prof.Falken elbette, ancak C kodu için değil, C ++ kodunun "aşağı doğru" uyumluluğunu sağlayabilmeyi amaçlayan bir tanımdır.
Arne Mertz

1

Bu yanıt, Arne'nin mantığının doğru olduğu bir durumdan esinlenmiştir. Bir satıcı, bir zamanlar hem C hem de C ++ 'yı destekleyen bir kitaplık yazdı; ancak en son sürüm yalnızca C'yi destekledi.

#ifdef __cplusplus
extern "C" {
#endif

Bu, C ++ 'da derlemeye çalışırken birkaç saatime mal oldu. Basitçe C ++ 'dan C'yi aramak çok daha kolaydı.

İfdef __cplusplus sözleşmesi, tek sorumluluk ilkesini ihlal etmektedir. Bu kuralı kullanan bir kod, aynı anda iki şey yapmaya çalışıyor:

  • (1) C - ve - 'de bir işlevi yürütün
  • (2) aynı işlevi C ++ 'da yürütün

Aynı anda hem Amerikan hem de İngiliz İngilizcesi yazmaya çalışmak gibi. Bu, gereksiz yere bir #ifdef __thequeensenglish anahtar #elif __yankeeenglish anahtarı #, kodu #endif'i kodun içine okumayı zorlaştıran işe yaramaz bir araç atıyor.

Basit kod ve küçük kitaplıklar için ifdef __cplusplus kuralı çalışabilir; ancak, karmaşık kitaplıklar için en iyisi bir dili veya diğerini seçmek ve ona bağlı kalmaktır. Dillerden birini desteklemek, her ikisini de desteklemeye çalışmaktan daha az bakım gerektirecektir.

Bu, Ubuntu Linux'ta derlemek için Arne'nin kodunda yaptığım değişikliklerin bir kaydı.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.