C ++-dakı extern "C" təsiri nədir?

C ++ extern "C" dəqiq qoyur?

Məsələn:

 extern "C" { void foo(); } 
1320
25 июня '09 в 5:10 2009-06-25 05:10 Laterum 25 iyun 2009-cu il saat 5 :10-da təyin olunur
@ 13 cavab

extern "C" C ++ funksiyasını "C" istinadına malikdir (derleyici adını dəyişdirmir), belə ki C kodunun kodu funksiyanı istinad edə bilər (funksiyanı istifadə etmək üçün) uyğun olan C uyğun başlıq faylını funksiyanızın yalnız bəyannaməsini ehtiva edir. Funksiyanızın tərifi müştərinin C-linkerinin "C" adı ilə istinad edəcəyi ikili formatda (sizin C ++ tərtibatçı tərəfindən hazırlanmışdır) yerləşdirilir.

C ++ funksiyası adlarının bir yüklənməsinə malik olduğundan, C deyilsə, C ++ kompilyatoru funksiyanın adını link üçün unikal identifikator kimi istifadə edə bilməz, belə ki, argumentlər haqqında məlumat əlavə edərək adını idarə edir. C funksiyasını C funksiyasını C ++-da bir "C" keçidinə malik olduğuna işarə etdiyində, C ++ tərtibçisi parametr parametrləri / parametrləri barədə məlumatı adına əlavə etmir, ünsiyyət üçün istifadə olunur.

Bildiyiniz kimi, hər bir fərdi reklam / müəyyən üçün "C" lövbəsini açıq şəkildə müəyyən edə bilərsiniz və ya xüsusi bir linkə malik olan bəyannamələrin / anlayışların sırasını qruplaşdırmaq üçün blok istifadə edə bilərsiniz:

 extern "C" void foo(int); extern "C" { void g(char); int i; } 

Texniki xüsusiyyətlərə diqqət yetirirsinizsə, onlar C ++ 03 standartının 7.5-ci bölməsində verilmişdir, burada tez bir baxış (extern "C" -ə diqqət yetirilir):

  • extern "C" - bağlama spesifikasiyası
  • Hər bir kompilyator "C"
  • məcburi spesifikasiya yalnız ad boşluğunda yerinə yetirilməlidir
  • bütün funksiyaların növləri, funksiya adları və dəyişən adları dil bağlıdır . Richardın şərhinə baxın: Yalnızca funksiya adları və xarici əlaqələri olan dəyişən adlar dil əlaqələri var.
  • müxtəlif linqvistik əlaqələri olan iki növ funksiya, bir-birinə eynidirlərsə belə fərqli tiplərdir
  • Xüsusiyyət İlişkisi Şartnamesi, daxili içərisində son əlaqəni təyin edir
  • Sınıf üzvləri üçün extern "C" sayılır
  • xüsusi bir adla birdən çox funksiya "C" istinadına (ad boşluğundan asılı olmayaraq)
  • extern "C" funksiyasını xarici bağlamaya səbəb olur (statik edə bilmir) . Richardın şərhinə baxın: "statik" içəridə 'extern' C '' etibarlıdır; bəyan edilmiş şəxsin daxili əlaqəsi vardır və buna görə də dil bağlayıcı deyildir
  • C ++-da digər dillərdə və C ++-da digər dillərdə müəyyən edilmiş obyektlərlə əlaqəli obyektlər tətbiq edilir və dil bağlıdır. Yalnız iki dil tətbiqinin obyektlərinin yerləşdirmə strategiyaları olduqca oxşar olduqda, bu cür əlaqələr əldə edilə bilər.
1309
25 июня '09 в 5:12 2009-06-25 05:12 Cavab Faisal Vali tərəfindən 25 iyun 2009-cu il tarixində 5:12, 2009-06-25 05:12 tarixində verilir

Hələ görmədiyimdən bəri bəzi məlumatlar əlavə etmək istədi.

C kodlarının çoxunu aşağıdakı kimi görürsünüz:

 #ifdef __cplusplus extern "C" { #endif // all of your legacy C code here #ifdef __cplusplus } #endif 

Bunun anlamı, bu C header faylını C ++ kodu ilə istifadə etməkdir, çünki "__cplusplus" makrosu müəyyən ediləcək. Ancaq siz onu köhnə C kodu ilə istifadə edə bilərsiniz, burada makro müəyyən edilmir, beləliklə, unikal C ++ quruluşunu görməyəcəkdir.

border=0

Baxmayaraq ki, mən də C ++ kodunu gördüm, məsələn:

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

İnanıram ki, eyni şeydir.

Hansı yolu yaxşı olduğuna əmin deyiləm, amma ikisini də görmüşəm.

263
21 окт. UncaAlby tərəfindən verilmiş cavab 21 oktyabr 2012-10-21 04:08 '12 at 4:08 2012-10-21 04:08

Hər C ++ proqramında, qeyri-statik funksiyalar ikili faylda simvol olaraq təqdim olunur. Bu simvollar bir proqramda funksiyanı unikal şəkildə müəyyən edən xüsusi mətn simləridır.

C'de, xarakter adı funksiyanın adı ilə eynidır. Bu mümkündür, çünki C-də qeyri-statik funksiyaların eyni adı ola bilər.

C ++-dən çox yüklənmişdir və C-nin olmadığı bir çox funksiyaya malik olduğundan - siniflər, üzv funksiyaları, istisnalar spesifikasiyaları kimi, sadəcə simvolu adı kimi funksiyanın adını istifadə etmək mümkün deyil. Bu problemi həll etmək üçün C ++ funksiyası adını və bütün zəruri məlumatları (məsələn, arqumentlərin sayı və ölçüsü) yalnız tərtibatçı və linker tərəfindən işlənən bir sıra qəribə simvol halına gətirən adı adını idarə edir.

Beləliklə, əgər extern C funksiyasını göstərsəniz, kompilyator adını yerinə yetirməyəcək və funksiyanı adı kimi simvolu adından istifadə etməklə birbaşa əldə edilə bilər.

Bu funksiyalardan istifadə etmək üçün dlsym()dlopen() istifadə edərkən faydalıdır.

183
25 июня '09 в 8:22 2009-06-25 08:22 cavab 25 iyun 25 iyun saat 08: 22 -da veriləcək

Nə baş verdiyini görmək üçün yaradılan g++ ikili faylını dekompilyasiya edin.

Giriş:

 void f() {} void g(); extern "C" { void ef() {} void eg(); }  void h() { g(); eg(); } 

GCC 4.8 Linux ELF versiyası ilə kompilyasiya edin:

 g++ -c a.cpp 

Simvol masasının dekompilyasiyası:

 readelf -s ao 

Çıxış aşağıdakıları ehtiva edir:

 Num: Value Size Type Bind Vis Ndx Name 8: 0000000000000000 6 FUNC GLOBAL DEFAULT 1 _Z1fv 9: 0000000000000006 6 FUNC GLOBAL DEFAULT 1 ef 10: 000000000000000c 16 FUNC GLOBAL DEFAULT 1 _Z1hv 11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z1gv 12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND eg 

şərh

Görürük ki:

  • efeg olduğu kimi eyni simvolda saxlanılır

  • digər simvollar təhrif edilmişdir. Onlarla razı olsunlar.

     $ c++filt _Z1fv f() $ c++filt _Z1hv h() $ c++filt _Z1gv g() 

Nəticə: hər iki simvol tipi təhrif edilməmişdir:

  • müəyyəndir
  • ( Ndx = UND ) bildirilmişdir, lakin başqa bir obyekt faylından istinad və ya iş zamanı təqdim edilməlidir

Beləliklə, zəng edərkən extern "C" ehtiyacınız olacaq:

  • C ++ 'dan C: g++ gcc yaratdığı düzəlməmiş simvolları gcc
  • C ++ 'dan C: gcc istifadə etmək üçün düzəlməmiş xarakterlər yaratmaq üçün g++ gcc

Xarici C'de işləməyən şeylər

Hər hansı bir C ++ funksiyası adı təhrif tələb edən extern C də işləməyəcəkdir:

 extern "C" { // Overloading. // error: declaration of C function 'void f(int) conflicts with void f(); void f(int i); // Templates. // error: template with C linkage template <class C> void f(C i) { } } 

C ++ nümunəsindəki minimum sağlam C

Orada tamamlama və yeniliklər naminə.

C ++ dan C-ə çağırılması olduqca sadədir: hər bir C funksiyası yalnız bir mümkün düzəlməmiş xarakter daşıyır, belə ki, heç bir əlavə iş tələb olunmur.

main.cpp:

 #include <cassert> #include "ch" int main() { assert(f() == 1); } 

h:

 #ifndef C_H #define C_H  #ifdef __cplusplus extern "C" { #endif int f(); #ifdef __cplusplus } #endif #endif 

cc:

 #include "ch" int f(void) { return 1; } 

Run:

 g++ -c -o main.o -std=c++98 main.cpp gcc -c -o co -std=c89 cc g++ -o main.out main.o co ./main.out 

extern "C" linki olmadan işləmir:

 main.cpp:6: undefined reference to 'f()' 

çünki g++ gcc istehsal etməmiş bir təhrif tapmaq üçün gözləyir.

Github haqqında bir nümunə .

C nümunəsindən C ++ minimum performans

C ++-dan axtarma bir az daha mürəkkəbdir: təqdim etmək istədiyimiz hər bir funksiyanı əl ilə düzəldilməmiş versiyalar yaratmalıyıq.

Burada C ++ funksiyasının yüklənməsini C.

main.c:

 #include <assert.h> #include "cpp.h" int main(void) { assert(f_int(1) == 2); assert(f_float(1.0) == 3); return 0; } 

cpp.h:

 #ifndef CPP_H #define CPP_H #ifdef __cplusplus // C cannot see these overloaded prototypes, or else it would get confused. int f(int i); int f(float i); extern "C" { #endif int f_int(int i); int f_float(float i); #ifdef __cplusplus } #endif #endif 

cpp.cpp:

 #include "cpp.h" int f(int i) { return i + 1; } int f(float i) { return i + 2; } int f_int(int i) { return f(i); } int f_float(float i) { return f(i); } 

Run:

 gcc -c -o main.o -std=c89 -Wextra main.c g++ -c -o cpp.o -std=c++98 cpp.cpp g++ -o main.out main.o cpp.o ./main.out 

extern "C" olmadan bu deyil:

 main.c:6: undefined reference to 'f_int' main.c:7: undefined reference to 'f_float' 

çünki g++ , gcc tapa bilmədiyi bozuk simvolları yaradır.

Github haqqında bir nümunə .

Ubuntu'da 18.04-də test edilmişdir.

148
29 мая '15 в 13:06 2015-05-29 13:06 Ciro Santilli'ye cavab verdi 改造 改造 中心 六四 事件 tövsiyə May 29, '15 at 13:06 2015-05-29 13:06

C ++, əməliyyat dilindən obyekt dili yaratmaq üçün funksiya adlarını dəyişdirir

Çox proqramlaşdırma dilləri mövcud proqramlaşdırma dilləri üzərində qurulmur. C ++ C-nin üstündə qurulmuşdur və bununla yanaşı prosessual proqramlaşdırma dilindən inşa edilmiş bir obyekt-o proqramlaşdırma dilidir və bu səbəbdən C. ilə C ++ açar sözlər, məsələn extern C ilə geri uyğunluq təmin edir.

Aşağıdakı nümunəyə nəzər salaq:

 #include <stdio.h> // Two functions are defined with the same name // but have different parameters void printMe(int a) { printf("int: %i\n", a); } void printMe(char a) { printf("char: %c\n", a); } int main() { printMe("a"); printMe(1); return 0; } 

AC derleyicisi yuxarıdakı nümunəni tərtib etmir, çünki printMe iki dəfə müəyyən edilmiş eyni printMe funksiyasıdır (fərqli parametrlər int a vs char a ).


1 PrintMe hatası birdən çox dəfə aşkarlanır.

C ++ tərtibçisi yuxarıda göstərilən nümunəni tərtib edir. printMe iki dəfə müəyyənləşdirilməməsi vacib deyildir.

Bu, C ++ kompilyatorunun parametrlərinə əsasən funksiyaları dolayısı ilə dəyişdirməyi ( təhrif edən ) olmasıdır. Bu funksiya C-də dəstəklənməmişdir. Lakin C ++ C-də inşa edildikdə, dil -o obyekti üçün nəzərdə tutulmuşdu və eyni adı olan metodlar (funksiyalar) ilə müxtəlif siniflər yaratmaq və metodları yenidən müəyyən etmək bacarığı olmalıdır (metodların yenidən təyin edilməsi ). a) müxtəlif parametrlərə əsaslanaraq.

Extern deyir: "Fəaliyyətlərin adlarını pozmayın"

Buna baxmayaraq, "parent.c" adlı bir köhnə C faylını təsəvvür edin ki, digər irsi C faylları, "parent.h", "child.h" və s. Köhnə fayl "parent.c" C ++ tərtibçisi tərəfindən işlədilirsə, funksiya adları təhrif olunacaq və artıq "parent.h", "child.h", və s. İlə göstərilən funksiya adlarına uyğun olmayacaq və funksiyanın adları bu xarici faylların da pozulması lazımdır. Bir çox asılılıqla kompleks bir C proqramında funksiya adlarını sifariş etmək kodun korrupsiyaya səbəb ola bilər; Buna görə də, C ++ tərtibçisini funksiyanın adını təhrif etməməyə imkan verə biləcək bir söz açmaq rahat ola bilər.

extern açar sözü, C ++ tərtibçisini funksiyanın adlarını təhrif etməmək (adını dəyişmək) demək deyil. Məsələn istifadə: extern void printMe(int a);

32
12 февр. cavab tfmontague 12 fevral verilir. 2017-02-12 04:50 '17 də 4:50 2017-02-12 04:50

Bu funksiyanı funksiyanı C-dən çağırmaqla dəyişə bilər. Praktikada bu, funksiyanın adını mangled deyil deməkdir.

24
25 июня '09 в 5:12 2009-06-25 05:12 Cavab 25 iyun 2009-cu il tarixində, 5: 12-də 2009-06-25 05:12 Rusiyada İşəgötürənə verilir

Heç bir C başlığı extern "C" istifadə etməklə tərtib olunacaq. C ++ açar sözləri ilə C-header münaqişəsində identifikatorlar olduqda, C ++ tərtibçisi bu barədə şikayət edəcəkdir.

Məsələn, aşağıdakı kodun g ++ 'da uğursuz olduğunu gördüm:

 extern "C" { struct method { int virtual; }; } 

Kinda mənada, amma C kodunu C ++ daşıyan zaman yadda saxlamaq lazımdır.

23
10 янв. Sander Mertens tərəfindən 10 yanvarda verilən cavab 2013-01-10 01:16 '13 'da 1:16' de 2013-01-10 01:16

C ++ kompilyatoru bu funksiyaların adlarını C stilində axtarmaq üçün izah edir, çünki C və C ++-də tərtib edilən funksiyaların adları birləşmə mərhələsində fərqlidir.

17
25 июня '09 в 5:12 2009-06-25 05:12 Mark Ruşakovun 25 iyun 2009- cu il tarixində 5:12 'də 2009-06-25 05:12 cavab verdi

extern "C" nin C ++ tərtibçisi tərəfindən tanınması nəzərdə tutulur və işarənin funksiyasını C stilində tərtib edən (və ya olmalıdır) kompilyatoru xəbərdar etmək üçün nəzərdə tutulur.

12
10 апр. Flami tərəfindən 10 apreldə cavab verildi 2012-04-10 12:46 '12 at 12:46 2012-04-10 12:46

DLL (dinamik link kitabxanaları) üçün "extern" C "" istifadə etdim. Əsas funksiyanı "ixrac edilə bilir", belə ki, daha sonra dll-dən başqa bir çalıştırılabilir faylda istifadə edilə bilər. Mən istifadə etdim, faydalı ola bilər.

Dll

 #include <string.h> #include <windows.h> using namespace std; #define DLL extern "C" __declspec(dllexport) //I defined DLL for dllexport function DLL main () { MessageBox(NULL,"Hi from DLL","DLL",MB_OK); } 

Exe

 #include <string.h> #include <windows.h> using namespace std; typedef LPVOID (WINAPI*Function)();//make a placeholder for function from dll Function mainDLLFunc;//make a variable for function placeholder int main() { char winDir[MAX_PATH];//will hold path of above dll GetCurrentDirectory(sizeof(winDir),winDir);//dll is in same dir as exe strcat(winDir,"\\exmple.dll");//concentrate dll name with path HINSTANCE DLL = LoadLibrary(winDir);//load example dll if(DLL==NULL) { FreeLibrary((HMODULE)DLL);//if load fails exit return 0; } mainDLLFunc=(Function)GetProcAddress((HMODULE)DLL, "main"); //defined variable is used to assign a function from dll //GetProcAddress is used to locate function with pre defined extern name "DLL" //and matcing function name if(mainDLLFunc==NULL) { FreeLibrary((HMODULE)DLL);//if it fails exit return 0; } mainDLLFunc();//run exported function FreeLibrary((HMODULE)DLL); } 
5
01 июля '14 в 18:43 2014-07-01 18:43 Cavab verilir: SturmCoder, 01 iyul '18: 18' da, 2014-07-01 18:43

extern "C" , Cpp mənbə fayllarında C çağırış funksiyaları üçün istifadə olunan məcburi xüsusiyyətdir. C funksiyalarına zəng edə bilərik , dəyişənləri yaza bilərik və başlıqları daxil edə bilərik. Funksiya extern varlıqda elan edilir və kənarda müəyyən edilir. Sintaksis

Tip 1:

 extern "> 

Tip 2:

 extern "> 

məsələn:

 #include<iostream> using namespace std; extern "C" { #include<stdio.h> // Include C Header int n; // Declare a Variable void func(int,int); // Declare a function (function prototype) } int main() { func(int a, int b); // Calling function . . . return 0; } // Function definition . . . void func(int m, int n) { // // } 
4
17 нояб. Yogeesh HT tərəfindən verilmiş cavab noyabrın 17-də 2015-11-17 15:09 '15 at 15:09 2015-11-17 15:09

C və C ++ (yəni C ++ və C-dən C ++ funksiyasını çağırmaq C) funksiyasını qarışdırdıqda, C ++ adının uğursuzluğu bağlanma ilə bağlı problemlərə səbəb olur. Texniki cəhətdən, bu problem yalnız çağrılan istifadəçinin funksiyaları artıq müvafiq kompilyatordan istifadə edərək ikili fayl (ən çox ehtimal * .a fayl) halında tərtib edildikdə baş verir.

Buna görə C ++-da ad manipulyasiyasını aradan qaldırmaq üçün extern "C" istifadə etmək lazımdır.

1
06 июля '17 в 7:04 2017-07-06 07:04 Cavab Trombe tərəfindən 06.07.2014 tarixində 7: 2017-07-06 07:04

Bu cavab səbirsizdir / yığıncaq üçün son tarixə malikdir, yalnız bir hissəsi / aşağıda açıqlama:

  • C ++-da, eyni şəkildə adındakı bir yükdə aşırı yükləmə üsulu ilə istifadə edə bilərsiniz (məsələn, onlar dll-dən ixrac edilə bilməyən adlarla eyni olduğundan və s.) bu problemlərin həlli fərqli (simvollar funksiyanın adını və arqumentləri ifadə edir, buna görə də eyni funksiyaların hər birinin eyni adı ilə eyni şəkildə müəyyən edilə bilər (həmçinin,
  • C-də yüklənməmisiniz, funksiyanın adı unikaldır (buna görə də funksiyanın adını müəyyən etmək üçün ayrı bir simli tələb olunmur, buna görə də simvol funksiyanın adıdır)

Beləliklə
C ++ 'da, hər bir funksiyanın kimliyini bənzər bir şəkildə müəyyən edən adla
C-də, hər bir funksiyanı şəxsiyyətləri müəyyən edən ad olmadan belə

C ++-nin davranışını dəyişdirmək üçün, yəni, müəyyən bir funksiya üçün adı manipulyasiya edilməməsi lazım olduğunu ifadə etmək üçün, hər hansı səbəbdən funksiyadan əvvəl extern "C" istifadə edə bilərsiniz, məsələn, müştərilər tərəfindən istifadə ediləcək DLL-dən xüsusi bir ad verin.

Daha ətraflı / daha düzgün cavab almaq üçün digər cavabları oxuyun.

1
24 июля '18 в 16:41 2018-07-24 16:41 Cavab Manohar Reddy Poreddy tərəfindən verilir 24 iyul '18, saat 16:41 'da 2018-07-24 16:41

tags ilə digər suallar, ya bir sual