C ++ හි බාහිර “C” හි බලපෑම කුමක්ද?


1656

හරියටම දමා නැත extern "C"C ++ කේතය කරන්නේ?

උදාහරණයක් වශයෙන්:

extern "C" {
   void foo();
}

84
මෙම ලිපිය ඔබට හඳුන්වා දීමට මම කැමතියි: http://www.agner.org/optimize/calling_conventions.pdf එය ඔබට සමුළුව කැඳවීම සහ සම්පාදකයින් අතර ඇති වෙනස ගැන තවත් බොහෝ දේ කියයි.
සෑම් ලියාඕ

1
@Litherum මගේ හිස මුදුනේ, එය හරස් සම්පාදකයෙකු ඇති බැවින්, C භාවිතා කරමින් එම කේතයේ විෂය පථය සම්පාදනය කරන ලෙස එය සම්පාදකයාට කියයි. එසේම, එයින් අදහස් වන්නේ ඔබ සතුව Cpp ගොනුවක් ඇති බවයි foo().
ha9u63ar

2
@ ha9u63ar එය 'මගේ හිස මුදුනෙන් ඉවතට'. ඔබගේ අදහස් දැක්වීමේ ඉතිරි කොටස ද වැරදිය. එය මකා දැමීමට මම නිර්දේශ කරමි.
TamaMcGlinn

Answers:


1582

බාහිර "C" මඟින් C ++ හි ක්‍රියාකාරී නාමයක් 'C' සම්බන්ධතාවයක් ඇති කරයි (සම්පාදකයාගේ නම හසුරුවන්නේ නැත) එවිට ග්‍රාහක C කේතයට 'C' අනුකූල ශීර්ෂ ගොනුවක් භාවිතා කර ඔබේ ශ්‍රිතයට සම්බන්ධ විය හැකිය (එනම් භාවිතා කරන්න) ඔබේ කාර්යය ප්‍රකාශ කිරීම. ඔබේ ක්‍රියාකාරී අර්ථ දැක්වීම ද්විමය ආකෘතියකින් (ඔබේ C ++ සම්පාදකයා විසින් සම්පාදනය කරන ලද) අඩංගු වන අතර එමඟින් සේවාදායකයා 'C' සම්බන්ධකය 'C' නම භාවිතා කිරීමට සම්බන්ධ වේ.

C ++ හි ක්‍රියාකාරී නම් අධික ලෙස පැටවීම සහ C නොමැති නිසා, C ++ සම්පාදකයාට ශ්‍රිත නාමය සම්බන්ධ කිරීම සඳහා අද්විතීය හැඳුනුම්පතක් ලෙස භාවිතා කළ නොහැක, එබැවින් එය තර්ක පිළිබඳ තොරතුරු එකතු කිරීමෙන් නම වෙනස් කරයි. සී හි ක්‍රියාකාරී නාමයන් අධික ලෙස පැටවිය නොහැකි බැවින් AC සම්පාදකයාට නම හැසිරවීමට අවශ්‍ය නොවේ. ශ්‍රිතයකට C ++ හි බාහිර "C" සම්බන්ධතාවයක් ඇති බව ඔබ ප්‍රකාශ කරන විට, C ++ සම්පාදකයා භාවිතා කරන නමට තර්ක / පරාමිති වර්ගයේ තොරතුරු එකතු නොකරයි. සම්බන්ධතාවය.

ඔබ දන්නා පරිදි, ඔබට එක් එක් ප්‍රකාශය / අර්ථ දැක්වීම සඳහා “සී” සම්බන්ධතාවය පැහැදිලිව සඳහන් කළ හැකිය, නැතහොත් නිශ්චිත සම්බන්ධතාවයක් ඇති කර ගැනීම සඳහා ප්‍රකාශන / අර්ථ දැක්වීම් මාලාවක් කාණ්ඩ කිරීමට බ්ලොක් එකක් භාවිතා කරන්න:

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

ඔබ තාක්ෂණික ක්‍රම ගැන සැලකිලිමත් වන්නේ නම්, ඒවා C ++ 03 ප්‍රමිතියේ 7.5 වගන්තියේ ලැයිස්තුගත කර ඇත, මෙහි කෙටි සාරාංශයක් ඇත (බාහිර "C" අවධාරණය කරමින්):

  • බාහිර "සී" යනු සම්බන්ධතා-පිරිවිතරයකි
  • සෑම සම්පාදකයෙකුටම "සී" සම්බන්ධතාවය සැපයීම අවශ්‍ය වේ
  • සම්බන්ධක පිරිවිතරයක් සිදුවන්නේ නාම අවකාශයේ පමණි
  • සියලුම ක්‍රියාකාරී වර්ග, ශ්‍රිත නම් සහ විචල්‍ය නම් වලට භාෂා සම්බන්ධතාවයක් ඇත. රිචඩ්ගේ අදහස බලන්න: බාහිර සම්බන්ධතා ඇති ක්‍රියාකාරී නම් සහ විචල්‍ය නම් පමණක් භාෂා සම්බන්ධතාවයක් ඇත
  • එකිනෙකට වෙනස් භාෂා සම්බන්ධතා ඇති ශ්‍රිත වර්ග දෙකක් වෙනත් ආකාරයකින් සමාන වුවත් වෙනස් ආකාර වේ
  • සම්බන්ධක පිරිවිතර කූඩුව, අභ්‍යන්තරය අවසාන සම්බන්ධතාවය තීරණය කරයි
  • පංතියේ සාමාජිකයින් සඳහා බාහිර "සී" නොසලකා හරිනු ලැබේ
  • කිසියම් නමක් ඇති එක් ශ්‍රිතයකට “සී” සම්බන්ධතාවයක් තිබිය හැකිය (නාම අවකාශය නොසලකා)
  • බාහිර "සී" මඟින් ශ්‍රිතයකට බාහිර සම්බන්ධතාවයක් ඇති කිරීමට බල කරයි (එය ස්ථිතික කළ නොහැක) රිචඩ්ගේ අදහස බලන්න: 'පිටත' සී 'ඇතුළත' ස්ථිතික 'වලංගු වේ; එසේ ප්‍රකාශිත ආයතනයකට අභ්‍යන්තර සම්බන්ධතාවයක් ඇති අතර භාෂා සම්බන්ධතාවයක් නොමැත
  • C ++ සිට වෙනත් භාෂාවලින් අර්ථ දක්වා ඇති වස්තූන් හා වෙනත් භාෂාවලින් C ++ හි අර්ථ දක්වා ඇති වස්තු සමඟ සම්බන්ධ කිරීම ක්‍රියාත්මක කිරීම-නිර්වචනය කර ඇති අතර භාෂාව මත රඳා පවතී. භාෂා ක්‍රියාත්මක කිරීම් දෙකක වස්තු පිරිසැලසුම් ක්‍රමෝපායන් ප්‍රමාණවත් තරම් සමාන වන විට පමණක් එවැනි සම්බන්ධතා ලබා ගත හැකිය

22
සී කම්පයිලර් විසින් සී ++ භාවිතා කරන මැන්ග්ලිං භාවිතා නොකරයි. එබැවින් ඔබට c ++ වැඩසටහනකින් ඇමතුම් ac අතුරුමුහුණත අවශ්‍ය නම්, c අතුරු මුහුණත "බාහිර c" ලෙස පැහැදිලිව ප්‍රකාශ කළ යුතුය.
සෑම් ලියාඕ

59
A ෆයිසල්: හරස් යොමු සියල්ලම 'බාහිර' සී '' වුවද, විවිධ සී ++ සම්පාදකයන් සමඟ සාදන ලද කේතය සම්බන්ධ කිරීමට උත්සාහ නොකරන්න. පංති පිරිසැලසුම්, හෝ ව්‍යතිරේකයන් හැසිරවීමට භාවිතා කරන යාන්ත්‍රණ හෝ විචල්‍යයන් භාවිතයට පෙර ආරම්භ කර ඇති බව සහතික කිරීම සඳහා භාවිතා කරන යාන්ත්‍රණයන් හෝ වෙනත් එවැනි වෙනස්කම් අතර බොහෝ විට වෙනස්කම් තිබේ, තවද ඔබට වෙනම C ++ ධාවන කාල ආධාරක පුස්තකාල දෙකක් අවශ්‍ය විය හැකිය (එකක් සඳහා එක් එක් සම්පාදකයා).
ජොනතන් ලෙෆ්ලර්

8
'බාහිර "සී" මඟින් ශ්‍රිතයකට බාහිර සම්බන්ධතා ඇති කිරීමට බල කරයි (එය ස්ථිතික කළ නොහැක)' වැරදිය. 'ස්ථිතික' ඇතුළත 'බාහිර "සී" වලංගු වේ; එසේ ප්‍රකාශිත ආයතනයකට අභ්‍යන්තර සම්බන්ධතාවයක් ඇති අතර භාෂා සම්බන්ධතාවයක් නොමැත.
රිචඩ් ස්මිත්

14
'සියලුම ශ්‍රිත වර්ග, ක්‍රියා නම් සහ විචල්‍ය නම් වලට භාෂා සම්බන්ධතාවයක් ඇත' ද වැරදිය. භාෂා සම්බන්ධතාවයක් ඇත්තේ ක්‍රියාකාරී නම් සහ බාහිර සම්බන්ධතා සහිත විචල්‍ය නම් පමණි.
රිචඩ් ස්මිත්

9
බව සටහන extern "C" { int i; }අර්ථ නිරූපනයක් වේ. නිර්වචනය නොකිරීමට යාබදව ඔබ අදහස් කළ දේ මෙය නොවිය හැකිය void g(char);. එය අර්ථ දැක්වීමක් නොවන බවට පත් කිරීමට ඔබට අවශ්‍ය වනු ඇත extern "C" { extern int i; }. අනෙක් අතට, සඟල වරහන් තොරව එක්-ප්රකාශය කාරක රීති ප්රකාශයට පත් නොවන අර්ථ දැක්වීම සිදු කරන්නේ: extern "C" int i;ම යextern "C" { extern int i; }
aschepler

328

මට තව තොරතුරු පළ කිරීමට අවශ්‍ය නැති නිසා, තොරතුරු ටිකක් එකතු කිරීමට අවශ්‍ය විය.

ඔබ බොහෝ විට C ශීර්ෂ වල කේතය දකිනු ඇත:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

මෙයින් ඉටු වන දෙය නම්, ඔබේ සී ++ කේතය සමඟ එම සී ශීර්ෂ ගොනුව භාවිතා කිරීමට ඔබට ඉඩ සලසයි, මන්ද සාර්ව "__cplusplus" යන්න අර්ථ දක්වනු ඇත. එහෙත්, ඔබ හැකි තවමත් එය සාර්ව වන ඔබේ උරුමය සී කේතය, සමග භාවිතා නොවේ අර්ථ, එය, සුවිශේෂ C ++ ඉදිකිරීමක් දැකිය නොහැක එසේ.

කෙසේ වෙතත්, මම C ++ කේතය ද දැක ඇත්තෙමි:

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

මම හිතන විදියටම එකම දේ ඉටු වේ.

වඩා හොඳ කුමන මාර්ගයදැයි විශ්වාස නැත, නමුත් මම දෙකම දැක ඇත්තෙමි.


11
පැහැදිලි වෙනසක් ඇත. කලින් සඳහන් කළ අවස්ථාවකදී, ඔබ මෙම ගොනුව සාමාන්‍ය gcc සම්පාදකයෙකු සමඟ සම්පාදනය කරන්නේ නම්, එමඟින් ශ්‍රිතයේ නම හසුරුවන්නේ නැති වස්තුවක් ජනනය වේ. ඔබ C සහ C ++ වස්තු සම්බන්ධකය සමඟ සම්බන්ධ කළහොත් එය ශ්‍රිත සොයා නොගනී. ඔබේ දෙවන කේත වාරණයේදී මෙන් බාහිර යතුරුපදය සමඟ එම “පැරණි ශීර්ෂක” ගොනු ඇතුළත් කිරීමට ඔබට අවශ්‍ය වනු ඇත.
ne න් වැන් රොසුම්

8
NAnne: C ++ සම්පාදකයා විසින් extern "C"ශීර්ෂ පා saw යේ දුටු නිසා පාලනය නොකළ නම් ද සොයනු ඇත ). එය විශිෂ්ට ලෙස ක්‍රියා කරයි, මෙම තාක්ෂණය බොහෝ වාරයක් භාවිතා කර ඇත.
බෙන් වොයිග්ට්

20
N ආන්: ඒක හරි නෑ, පළවෙනි එකත් හොඳයි. එය C සම්පාදකයා විසින් නොසලකා හරින අතර C ++ හි දෙවැන්න හා සමාන බලපෑමක් ඇති කරයි. සම්පාදකයාට extern "C"එය ශීර්ෂකය ඇතුළත් කිරීමට පෙර හෝ පසුව හමුවන්නේද යන්න අඩු සැලකිල්ලක් දැක්විය නොහැක . එය සම්පාදකයා වෙත ළඟා වන විට, එය කෙසේ හෝ පෙර සැකසූ පෙළක එක් දිගු ප්‍රවාහයක් පමණි.
බෙන් වොයිග්ට්

8
N ආන්, නැත, මම සිතන්නේ ඔබ ප්‍රභවයේ වෙනත් දෝෂයක් නිසා පීඩාවට පත්ව ඇති බවයි, මන්ද ඔබ විස්තර කරන දේ වැරදිය. කිසිදු අනුවාදය g++අවම වශයෙන් වසර 17 කට ඕනෑම වේලාවක ඕනෑම ඉලක්කයක් සඳහා, මෙම වැරදි විය. පළමු උදාහරණයේ සමස්ත කරුණ නම්, ඔබ සී හෝ සී ++ සම්පාදකයෙකු භාවිතා කළත් කමක් නැත, extern "C"බ්ලොක් එකේ නම් සඳහා නම් මැන්ග්ලිං කිරීමක් සිදු නොවේ .
ජොනතන් වේක්ලි

7
"කුමන එකක් වඩා හොඳද" - නිසැකවම, පළමු ප්‍රභේදය වඩා හොඳය: සී සහ සී ++ කේත දෙකෙහිම තවත් අවශ්‍යතා නොමැතිව ශීර්ෂකය කෙලින්ම ඇතුළත් කිරීමට එය ඉඩ දෙයි. දෙවන ප්‍රවේශය C ශීර්ෂයන් සඳහා වන ක්‍රියාමාර්ගයකි. කතුවරයාට C ++ ආරක්ෂකයින් අමතක වී ඇත (ගැටළුවක් නැත, නමුත් මේවා පසුව එකතු කළ හොත්, කූඩුවල බාහිර "C" ප්‍රකාශ පිළිගනු ලැබේ ...).
ඇකොන්කගුවා

272

සිදුවන්නේ g++කුමක්දැයි බැලීමට ජනනය කරන ලද ද්විමය විසංයෝජනය කරන්න

main.cpp

void f() {}
void g();

extern "C" {
    void ef() {}
    void eg();
}

/* Prevent g and eg from being optimized away. */
void h() { g(); eg(); }

ජනනය කරන ලද ELF ප්‍රතිදානය සම්පාදනය කර විසුරුවා හරින්න :

g++ -c -std=c++11 -Wall -Wextra -pedantic -o main.o main.cpp
readelf -s main.o

ප්‍රතිදානයේ අඩංගු වන්නේ:

     8: 0000000000000000     7 FUNC    GLOBAL DEFAULT    1 _Z1fv
     9: 0000000000000007     7 FUNC    GLOBAL DEFAULT    1 ef
    10: 000000000000000e    17 FUNC    GLOBAL DEFAULT    1 _Z1hv
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z1gv
    13: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND eg

අර්ථ නිරූපණය

අපට එය පෙනේ:

  • efහා egකේතය දී මෙන් ම නම සංකේත තුළ ගබඩා කර ඇත

  • අනෙක් සංකේත අඹරන ලදි. අපි ඒවා පාලනය නොකරමු:

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

නිගමනය: පහත දැක්වෙන සංකේත වර්ග දෙකම අඹරන ලද්දේ නැත :

  • අර්ථ දක්වා ඇත
  • ප්‍රකාශිත නමුත් නිර්වචනය නොකළ ( Ndx = UND), වෙනත් වස්තු ගොනුවකින් සබැඳිය හෝ ක්‍රියාත්මක වේලාවට සැපයීමට

එබැවින් ඇමතීමේදී ඔබට extern "C"දෙකම අවශ්‍ය වේ :

  • C ++ වෙතින් C: g++විසින් නිපදවන ලද පාලනය නොකළ සංකේත අපේක්ෂා කිරීමට කියන්නgcc
  • C වෙතින් C ++: භාවිතා කිරීම g++සඳහා පාලනය නොකළ සංකේත ජනනය කිරීමට කියන්නgcc

බාහිර C හි ක්‍රියා නොකරන දේවල්

නම මැන්ග්ලිං අවශ්‍ය ඕනෑම C ++ අංගයක් ඇතුළත ක්‍රියා නොකරන බව පැහැදිලිය extern C:

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 ++ උදාහරණයෙන් ධාවනය කළ හැකි අවම සී

සම්පූර්ණත්වය සහ එහි ඇති නවකයන් සඳහා, මෙයද බලන්න: C ++ ව්‍යාපෘතියක C ප්‍රභව ගොනු භාවිතා කරන්නේ කෙසේද?

C ++ වෙතින් C ඇමතීම පහසුය: සෑම C ශ්‍රිතයකටම ඇත්තේ එක් කළ නොහැකි සංකේතයක් පමණි, එබැවින් අමතර වැඩක් අවශ්‍ය නොවේ.

main.cpp

#include <cassert>

#include "c.h"

int main() {
    assert(f() == 1);
}

ch

#ifndef C_H
#define C_H

/* This ifdef allows the header to be used from both C and C++ 
 * because C does not know what this extern "C" thing is. */
#ifdef __cplusplus
extern "C" {
#endif
int f();
#ifdef __cplusplus
}
#endif

#endif

cc

#include "c.h"

int f(void) { return 1; }

ධාවනය:

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

extern "C"සබැඳිය නොමැතිව අසමත් වන්නේ:

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

මක්නිසාද යත් , නිපදවා නැති , g++අඹ ගෙඩියක් සොයා ගැනීමට අපේක්ෂා කරන බැවිනි .fgcc

GitHub හි උදාහරණය .

සී උදාහරණයෙන් ධාවනය කළ හැකි අවම C ++

C වෙතින් 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);
}

ධාවනය:

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"එය නොමැතිව අසමත් වේ:

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

නිසා g++ඇති තැලී පොඩි වී ගිය සංකේත ජනනය gccකළ හැකි වැඩක් නැහැ.

GitHub හි උදාහරණය .

උබුන්ටු 18.04 හි පරීක්ෂා කර ඇත.


21
ඔබ සිට ඇති හොඳම පිළිතුර 1) සී ++ වැඩසටහන් තුළ සිට පාලනය නොකළ සී ශ්‍රිතයන් මෙන්ම සී වැඩසටහන් තුළ සිට පාලනය නොකළ සී ++ ශ්‍රිතයන්extern "C" { ඇමතීමට උපකාරී වන බව පැහැදිලිව සඳහන් කරන්න , අනෙක් පිළිතුරු එතරම් පැහැදිලිව නොපෙන්වයි , සහ 2) ඔබ පැහැදිලි උදාහරණ පෙන්වන නිසා සෑම. ස්තූතියි!
ගේබ්‍රියෙල් ස්ටැපල්ස්

3
මම මෙම පිළිතුරට බෙහෙවින් කැමතියි
selfboot

4
C
Gaspa79

1
AveJaveneCPPMcGowan මට C ++ ගුරුවරයෙක් සිටියා යැයි ඔබ සිතන්නේ කුමක්ද? :-)
සීරෝ සැන්ටිලි 郝海东 冠状 病 六四 事件 法轮功

205

සෑම C ++ වැඩසටහනකදීම, සියලු ස්ථිතික නොවන කාර්යයන් ද්විමය ගොනුවේ සංකේත ලෙස නිරූපණය කෙරේ. මෙම සංකේත වැඩසටහනේ ශ්‍රිතයක් අද්විතීය ලෙස හඳුනා ගන්නා විශේෂ පෙළ නූල් වේ.

C හි, සංකේත නාමය ශ්‍රිත නාමයට සමාන වේ. මෙය කළ හැකි වන්නේ සී හි ස්ථිතික නොවන ශ්‍රිත දෙකකට එකම නමක් තිබිය නොහැකි බැවිනි.

C ++ වැඩිපුර පැටවීමට ඉඩ දී ඇති අතර C ට නොයන බොහෝ විශේෂාංග - පන්ති, සාමාජික කාර්යයන්, ව්‍යතිරේක පිරිවිතර වැනි - ක්‍රියාකාරී නාමය සංකේත නාමයක් ලෙස සරලව භාවිතා කළ නොහැක. එය විසඳීම සඳහා, C ++ ඊනියා නාම මැන්ග්ලිං භාවිතා කරයි, එමඟින් ක්‍රියාකාරී නාමය සහ අවශ්‍ය සියලු තොරතුරු (තර්කවල අංකය හා ප්‍රමාණය වැනි) සම්පාදකයා සහ සම්බන්ධකය විසින් පමණක් සකසන ලද අමුතු පෙනුමක් ඇති නූල් බවට පරිවර්තනය කරයි.

එබැවින් ඔබ බාහිර C ලෙස ශ්‍රිතයක් නියම කරන්නේ නම්, සම්පාදකයා එය සමඟ නම හැසිරවීම සිදු නොකරන අතර එහි සංකේත නාමය ශ්‍රිත නාමය ලෙස සෘජුවම ප්‍රවේශ කළ හැකිය.

එවැනි කාර්යයන් භාවිතා කිරීමේදී dlsym()සහ ඇමතීමේදී මෙය ප්‍රයෝජනවත් dlopen()වේ.


ඔබ හුරුබුහුටි ලෙස අදහස් කරන්නේ කුමක්ද? සංකේත නාමය = ශ්‍රිත නාමය මඟින් සංකේත නාමය dlsym වෙත ලබා දෙනු ඇත, නැතහොත් වෙනත් දෙයක්ද?
දෝෂය

1
දෝෂය: ඔව්. () සී ++ හවුල් පුස්තකාලයක් ශීර්ෂ ගොනුවක් පමණක් ලබා දී පැටවීම සඳහා නිවැරදි ශ්‍රිතය තෝරා ගැනීම සාමාන්‍යයෙන් කළ නොහැක්කකි. (X86 මත, එහි Itanium ABI ස්වරූපයෙන් පළ නම-mangling පිරිවිතර මම mangle C ++ කාර්යය නම් කිරීමට භාවිත දන්නේ x86 අවස්තා බව, නමුත් භාෂාවෙන් කිසිවක් අවශ්ය වේ.)
ජොනතන් Tomer

52

කාර්ය පටිපාටික භාෂාවකින් වස්තු-නැඹුරු භාෂාවක් නිර්මාණය කිරීම සඳහා C ++ මැන්ගල්ස් ක්‍රියාකාරී නම්

බොහෝ ක්‍රමලේඛන භාෂාවන් දැනට පවතින ක්‍රමලේඛන භාෂාවන් මත ගොඩනගා නොමැත. C ++ සෑදී ඇත්තේ C ට ඉහළින් වන අතර තව දුරටත් එය ක්‍රියාපටිපාටි ක්‍රමලේඛන භාෂාවකින් සාදන ලද වස්තු-නැඹුරු ක්‍රමලේඛන භාෂාවකි. එම හේතුව නිසා C ++ ප්‍රකාශන C extern "C"සමඟ පසුගාමී අනුකූලතාවයක් සපයයි.

පහත උදාහරණය දෙස බලමු:

#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 සම්පාදකයා ඉහත උදාහරණය සම්පාදනය නොකරනු ඇත, මන්ද එකම ශ්‍රිතය printMeදෙවරක් අර්ථ දක්වා ඇත (ඒවාට int aඑදිරිව විවිධ පරාමිතීන් තිබුණද char a).

gcc -o printMe printMe.c && ./printMe;
1 දෝෂයකි. PrintMe එක වරකට වඩා අර්ථ දක්වා ඇත.

C ++ සම්පාදකයෙකු ඉහත උදාහරණය සම්පාදනය කරයි. එය printMeදෙවරක් අර්ථ දක්වා ඇති බවක් ගණන් ගන්නේ නැත .

g ++ -o printMe printMe.c && ./printMe;

මෙයට හේතුව C ++ සම්පාදකයෙකු ඒවායේ පරාමිතීන් මත පදනම්ව ව්‍යංගයෙන් ( මැංගල්ස් ) ක්‍රියා කරන බවයි. C හි, මෙම අංගයට සහය නොදක්වයි. කෙසේ වෙතත්, C ++ C හරහා ගොඩනඟන විට, භාෂාව නිර්මාණය කර ඇත්තේ වස්තු-නැඹුරු වන අතර, එකම නමේ ක්‍රම (ශ්‍රිත) සමඟ විවිධ පංති නිර්මාණය කිරීමේ හැකියාව සහ විවිධ මත පදනම්ව ක්‍රම ( ක්‍රම ඉක්මවා යාම ) අභිබවා යාමට අවශ්‍ය විය. පරාමිතීන්.

extern "C" "සී ශ්‍රිත නාමයන් හසුරුවන්න එපා"

කෙසේ වෙතත්, අපට "parent.c" නමින් පැරණි C ගොනුවක් ඇති බව සිතන්න, includeඑය වෙනත් උරුම C ගොනු, "parent.h", "child.h" යනාදියෙහි ක්‍රියාකාරී නම් වේ. උරුමය "parent.c" ගොනුව ක්‍රියාත්මක වන්නේ නම් C ++ සම්පාදකයෙකු හරහා, එවිට ශ්‍රිත නාමයන් හසුරුවනු ඇති අතර, ඒවා තවදුරටත් "parent.h", "child.h" යනාදියෙහි දක්වා ඇති ක්‍රියාකාරී නම් සමඟ නොගැලපේ - එබැවින් එම බාහිර ලිපිගොනු වල ක්‍රියාකාරී නම් ද අවශ්‍ය වේ. අඹරන්න. සංකීර්ණ සී වැඩසටහනක් හරහා ක්‍රියාකාරී නාමයන් ඇලවීම, බොහෝ පරායත්තතා ඇති අය, බිඳුණු කේතයකට තුඩු දිය හැකිය; එබැවින් C ++ සම්පාදකයාට ක්‍රියාකාරී නාමයක් හසුරුවන්න එපා යැයි පැවසිය හැකි යතුරු පදයක් සැපයීම පහසු විය හැකිය.

මෙම extern "C"මූල පදය නොවන mangle (ප්රතිනම්කෙරුම්) සී කාර්යය නම් කිරීමට C ++ compiler කියයි.

උදාහරණයක් වශයෙන්:

extern "C" void printMe(int a);


අපට ගොනුවක් extern "C"තිබේ නම් අපට භාවිතා කළ dllනොහැකිද? මම අදහස් කළේ අපට ශීර්ෂ ගොනුවක් නොමැති නම් සහ ප්‍රභව ගොනුවක් (ක්‍රියාත්මක කිරීම් පමණක්) තිබේ නම් සහ එහි ක්‍රියාකාරීත්වය ශ්‍රිත දර්ශකය හරහා භාවිතා කිරීමයි. මෙම තත්වය තුළ, අපි කාර්යයන් භාවිතා කළෙමු (එහි නම නොසලකා).
BattleTested

ftfmontague, මට නම් ඔබ එය ඇණ ගැසුවා! කෙලින්ම හිසෙහි.
අර්ටානිස් සෙරතුල්

29

බාහිර "C" වලින් ඔතා ඕනෑම C- ශීර්ෂයක් C ++ සමඟ අනුකූල විය නොහැක. C ++ මූල පද සමඟ C-header ගැටුමක හඳුනාගැනීම් C ++ සම්පාදකයා මේ ගැන පැමිණිලි කරනු ඇත.

උදාහරණයක් ලෙස, g ++ හි පහත කේතය අසමත් වන බව මම දැක ඇත්තෙමි:

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

Kinda තේරුමක් ඇති නමුත් C ++ වෙත C කේතය වරාය කිරීමේදී මතක තබා ගත යුතු දෙයකි.


14
extern "C"වෙනත් පිළිතුරු වලින් විස්තර කර ඇති පරිදි සී සම්බන්ධතාවය භාවිතා කිරීම යන්නෙන් අදහස් කෙරේ. "අන්තර්ගතය සී ලෙස සම්පාදනය කිරීම" හෝ කිසිවක් අදහස් නොකෙරේ. int virtual;C ++ හි වලංගු නොවන අතර විවිධ සම්බන්ධතා සඳහන් කිරීමෙන් එය වෙනස් නොවේ.
එම් එම්

1
... හෝ සාමාන්‍යයෙන් මාදිලිය, සින්ටැක්ස් දෝෂයක් ඇති ඕනෑම කේතයක් සම්පාදනය නොකරයි.
වැලන්ටින් හයිනිට්ස්

4
@ValentinHeinitz ස්වාභාවිකවම, C හි හඳුනාගැනීමක් ලෙස "අතථ්‍ය" භාවිතා කිරීම සින්ටැක්ස් දෝෂයක් නොවේ. මට අවශ්‍ය වූයේ C ++ හි කිසිදු C ශීර්ෂයක් ස්වයංක්‍රීයව භාවිතා කළ නොහැකි බව ය.
සැන්ඩර් මර්ටෙන්ස්

28

එය ශ්‍රිතයේ සම්බන්ධතාවය සී වෙතින් කැඳවිය හැකි ආකාරයට වෙනස් කරයි. ප්‍රායෝගිකව එයින් අදහස් වන්නේ ශ්‍රිත නාමය අක්‍රීය නොවන බවයි.


3
Mangled යනු සාමාන්‍යයෙන් භාවිතා වන යෙදුමයි ... මෙම අර්ථය සමඟ 'සැරසිලි' කර ඇති බව මා දැක ඇති බව විශ්වාස නොකරන්න.
මැතිව් ෂාර්ලි

2
මයික්‍රොසොෆ්ට් (අවම වශයෙන් අර්ධ වශයෙන්) ඔවුන්ගේ ලියකියවිලි වල අඹරනවාට වඩා සරසා ඇත . ඔවුන් තම මෙවලම නමක් අවතක්සේරු කිරීමට (අකා-මැන්ගල්) පවා නම් කරති undname.
රෙනේ නිෆෙනෙගර්

20

සම්බන්ධ වන විට C හා C ++ වලින් සම්පාදනය කරන ලද ශ්‍රිතයන්ගේ නම් වෙනස් වන බැවින් එය C ++ සම්පාදකයාට C- ශෛලියක් තුළ සොයා බැලීමට දැනුම් දෙයි.


11

extern "C" සී ++ සම්පාදකයෙකු විසින් හඳුනා ගැනීමටත්, කැපී පෙනෙන ශ්‍රිතය සී ශෛලියෙන් සම්පාදනය කර ඇති බවට සම්පාදකයාට දැනුම් දීමටත්, එමඟින් සම්බන්ධ වන විට එය සී වෙතින් ශ්‍රිතයේ නිවැරදි අනුවාදයට සම්බන්ධ වේ.


6

extern "C"යනු Cpp ප්‍රභව ලිපිගොනු වල C ශ්‍රිත ඇමතීමට භාවිතා කරන සම්බන්ධක පිරිවිතරයකි . අපට C ශ්‍රිත ඇමතිය හැකිය , විචල්‍යතා ලිවිය හැකිය, සහ ශීර්ෂ ඇතුළත් කළ හැකිය. කාර්යය බාහිර වස්තුවෙන් ප්‍රකාශයට පත් කරන අතර එය පිටත අර්ථ දක්වා ඇත. සින්ටැක්ස් වේ

1 වර්ගය:

extern "language" function-prototype

2 වර්ගය:

extern "language"
{
     function-prototype
};

උදා:

#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)
{
    //
    //
}

5

ඩීඑල් (ගතික සම්බන්ධක පුස්තකාල) ලිපිගොනු ආදිය සෑදීම සඳහා මම මීට පෙර 'බාහිර' සී '' භාවිතා කළෙමි. සමහර විට මම එය භාවිතා කළ ස්ථානය පිළිබඳ උදාහරණයක් ප්‍රයෝජනවත් විය හැකිය.

ඩී.එල්.එල්

#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);
}

4
ව්‍යාජ. extern "C"හා __declspec(dllexport)සම්බන්ධයක් නැති වේ. කලින් පාලනය කළ සංකේත සැරසිලි, දෙවැන්න අපනයන ප්‍රවේශයක් නිර්මාණය කිරීමේ වගකීම දරයි. ඔබට C ++ නාම සැරසිලි භාවිතයෙන් සංකේතයක් අපනයනය කළ හැකිය. මෙම ප්‍රශ්නයේ කාරණය මුළුමනින්ම මග හැරී ඇතිවාට අමතරව, කේත නියැදියේ වෙනත් වැරදි ද තිබේ. එකක් නම්, mainඔබේ ඩීඑල්එල් වෙතින් අපනයනය කළ ප්‍රතිලාභ ප්‍රතිලාභයක් ප්‍රකාශ නොකරයි. නැතහොත් සමුළුව කැඳවීම, ඒ සඳහා. ආයාත කරන විට, ඔබ අහඹු ඇමතුම් සම්මුතියක් ( WINAPI) ආරෝපණය කරන අතර , බිට් 32 ගොඩනැගීම සඳහා වැරදි සංකේතය භාවිතා කරන්න (විය යුතුය _mainහෝ විය යුතුය _main@0). කණගාටුයි, -1.
හඳුනාගත නොහැකි

1
එය පුනරාවර්තනය වන්නේ, ඔබ නොදන්නා, ඔබ කරන්නේ කුමක්ද, නමුත් මේ ආකාරයෙන් එය කිරීම ඔබ වෙනුවෙන් වැඩ කරන බවක් පෙනේ, ඉලක්කගත වේදිකා වල අනාවරණය නොකළ ලැයිස්තුවක් සඳහා. මගේ පෙර අදහස් දැක්වීමේදී මා මතු කළ ගැටළු ඔබ ආමන්ත්‍රණය කළේ නැත. අතිශය වැරැදි නිසා මෙය තවමත් අඩු ඡන්දයකි (තවත් බොහෝ දේ ඇත, එය එක විවරණයකටවත් නොගැලපේ).
හඳුනාගත නොහැකි

1
තොග පිටාර ගැලීම පිළිබඳ පිළිතුරක් පළ කිරීමෙන් ඇඟවෙන්නේ ඔබ කරන්නේ කුමක්ද යන්න ඔබ දන්නා බවයි. මෙය අපේක්ෂා කෙරේ. "ධාවනය වන විට සිදුවන දූෂණය වැළැක්වීමට" ඔබ දරන උත්සාහය සම්බන්ධයෙන් : ඔබේ ක්‍රියාකාරී අත්සන මඟින් වර්ගයෙහි ප්‍රතිලාභ අගය නියම කරයි void*, නමුත් ඔබේ ක්‍රියාත්මක කිරීම කිසිවක් ආපසු ලබා නොදේ. එය ඉතා හොඳින් පියාසර කරනු ඇත ...
හඳුනාගත නොහැකි

1
ඔබට යමක්, එය කියාත්මක නම් පෙනෙන්නට වැඩ කිරීමට, පවිත්ර, වාසනාව විසින්, ඔබ පැහැදිලිව නැහැ නැහැ කියලා ඔබ කරන්නේ කුමක්ද (ඔබගේ "" වැඩ නියැදියක් යමකි.) එය නිර්වචනය නොකළ හැසිරීමක් වන අතර රැකියාවට පෙනී සිටීම වලංගු නොවන හැසිරීමකි. එය තවමත් නිර්වචනය කර නැත. ඔබ අනාගතයේ දී වැඩි කඩිසරකමක් දැක්වුවහොත් මම එය බෙහෙවින් අගය කරමි. එයින් කොටසක් මෙම යෝජිත පිළිතුර මකා දැමිය හැකිය.
හඳුනාගත නොහැකි

1
ඔබ කිසිවක් නැවත නොදක්වන ශ්‍රිතයක් නැවත අර්ථකථනය කරන්නේ දර්ශකයක් ලබා දෙන ශ්‍රිතයක් ලෙස ය. ක්‍රියාකාරී අත්සන නොගැලපීම හා විශේෂයෙන් සමෝධානික වර්ගයේ ප්‍රතිලාභ අගයන් සම්බන්ධයෙන් x86 ඉතා සමාව දීම පිරිසිදු වාසනාවකි. ඔබේ කේතය ක්‍රියාත්මක වන්නේ අහම්බෙන් පමණි. ඔබ එකඟ නොවන්නේ නම්, ඔබේ කේතය විශ්වසනීයව ක්‍රියාත්මක වන්නේ මන්දැයි ඔබ පැහැදිලි කළ යුතුය.
හඳුනාගත නොහැකි

3

මෙම පිළිතුර නොඉවසිලිමත් / හමුවීමට නියමිත දින නියමයන් ඇත, පහත දැක්වෙන්නේ කොටසක් / සරල පැහැදිලි කිරීමක් පමණි:

  • C ++ හි, ඔබට අධික බර පැටවීමෙන් පන්තියේ එකම නමක් තිබිය හැකිය (නිදසුනක් ලෙස, ඒවා සියල්ලම එකම නම වන බැවින් dll වලින් අපනයනය කළ නොහැක.) මෙම ගැටළුවලට විසඳුම වන්නේ ඒවා විවිධ නූල් වලට පරිවර්තනය කිරීමයි (සංකේත ලෙස හැඳින්වේ) ), සංකේත මඟින් ශ්‍රිතයේ නම සහ තර්ක ද ඇතුළත් වේ, එබැවින් මෙම සෑම ශ්‍රිතයක්ම එකම නමකින් වුවද අද්විතීය ලෙස හඳුනාගත හැකිය (නම මැන්ග්ලිං ලෙසද හැඳින්වේ)
  • C හි, ඔබට අධි බර පැටවීමක් නොමැත, ශ්‍රිත නාමය අද්විතීය වේ (එබැවින්, ශ්‍රිත නාමය අද්විතීය ලෙස හඳුනා ගැනීම සඳහා වෙනම නූලක් අවශ්‍ය නොවේ, එබැවින් සංකේතය යනු ශ්‍රිත නාමයයි)

එබැවින්
C ++ හි, නම මැන්ග්ලිං සමඟ
C හි එක් එක් ශ්‍රිතය අද්විතීය ලෙස හඳුනා ගනී, නම මැන්ග්ලිං නොමැතිව පවා එක් එක් ශ්‍රිතය අද්විතීය ලෙස හඳුනා ගනී

C ++ හි හැසිරීම වෙනස් කිරීම සඳහා, එනම්, විශේෂිත ශ්‍රිතයක් සඳහා මැන්ග්ලිං සිදු නොවිය යුතු බව සඳහන් කිරීමට, ශ්‍රිත නාමයට පෙර බාහිර "C" භාවිතා කළ හැකිය , කුමන හේතුවක් නිසා හෝ dll වෙතින් නිශ්චිත නමක් සහිත ශ්‍රිතයක් අපනයනය කිරීම වැනි , එහි සේවාදායකයින්ගේ භාවිතය සඳහා.

වඩාත් සවිස්තරාත්මක / වඩාත් නිවැරදි පිළිතුරු සඳහා වෙනත් පිළිතුරු කියවන්න.


1

C සහ C ++ මිශ්‍ර කරන විට (එනම්, C ++ වෙතින් C ශ්‍රිතය ඇමතීම; සහ b. C වෙතින් C ++ ශ්‍රිතය ඇමතීම), C ++ නාම මැන්ග්ලිං සම්බන්ධ කිරීමේ ගැටළු ඇති කරයි. තාක්ෂණික වශයෙන් ගත් කල, මෙම ගැටළුව සිදුවන්නේ අනුරූප සම්පාදකයා භාවිතා කරමින් ඇමතුම් ශ්‍රිත දැනටමත් ද්විමය (බොහෝ විට * .a පුස්තකාල ගොනුවකට) සම්පාදනය කර ඇති විට පමණි.

එබැවින් C ++ හි මැන්ග්ලිං යන නම අක්‍රීය කිරීමට බාහිර "සී" භාවිතා කළ යුතුය.


0

වෙනත් හොඳ පිළිතුරු සමඟ ගැටීමෙන් තොරව, මම මගේ ආදර්ශය ටිකක් එකතු කරමි.

හරියටම C ++ සම්පාදකයා කරන්නේ කුමක්ද: එය සම්පාදන ක්‍රියාවලියේ නම් හසුරුවයි, එබැවින් ක්‍රියාත්මක කිරීමට විශේෂයෙන් සැලකීමට සම්පාදකයාට පැවසීම අවශ්‍ය වේ C.

අපි C ++ පන්ති සාදා එකතු කරන විට extern "C", අපි C ඇමතුම් සම්මුතිය භාවිතා කරන බව අපගේ C ++ සම්පාදකයාට කියමු.

හේතුව (අපි C ++ සිට C ක්‍රියාත්මක කිරීම ලෙස හඳුන්වන්නෙමු ): එක්කෝ අපට C ++ වෙතින් C ශ්‍රිතය ඇමතීමට හෝ C වෙතින් C ++ ශ්‍රිතය ඇමතීමට අවශ්‍ය වේ (C ++ පන්ති ... ආදිය C හි ක්‍රියා නොකරයි).


තොග පිටාර ගැලීම වෙත සාදරයෙන් පිළිගනිමු. හොඳින් තහවුරු වී ඇති නිවැරදි පිළිතුරක් ඇති පැරණි ප්‍රශ්නයකට පිළිතුරු දීමට ඔබ තීරණය කරන්නේ නම්, දවසේ අග භාගයේ නව පිළිතුරක් එක් කිරීමෙන් ඔබට කිසිදු ගෞරවයක් නොලැබෙනු ඇත. ඔබ සතුව සුවිශේෂී නව තොරතුරු තිබේ නම්, හෝ අනෙක් පිළිතුරු සියල්ලම වැරදියි කියා ඔබට ඒත්තු ගැන්වී ඇත්නම්, සෑම අතින්ම නව පිළිතුරක් එක් කරන්න, නමුත් 'තවත් පිළිතුරක්' එකම මූලික තොරතුරු ලබා දීමෙන් ප්‍රශ්නය ඇසීමෙන් බොහෝ කලකට පසු සාමාන්‍යයෙන් ජය ගනී ' ඔබට බොහෝ ගෞරවය උපයා ගත නොහැක. අවංකවම, මම හිතන්නේ නැහැ මේ පිළිතුරේ අලුත් දෙයක් නැහැ.
ජොනතන් ලෙෆ්ලර්

-1

සී සම්පාදකයෙකු විසින් සම්පාදනය කරන ලද ශ්‍රිත අවලංගු f () සහ සී ++ සම්පාදකයෙකු විසින් සම්පාදනය කරන ලද එකම නම සහිත ශුන්‍ය f () ශ්‍රිතයක් එකම ශ්‍රිතයක් නොවේ. ඔබ එම ශ්‍රිතය C හි ලියා, පසුව ඔබ එය C ++ වෙතින් ඇමතීමට උත්සාහ කළේ නම්, සම්බන්ධකය C ++ ශ්‍රිතය සොයනු ඇති අතර C ශ්‍රිතය සොයා නොගනී.

බාහිර "සී" සී ++ සම්පාදකයාට පවසන්නේ ඔබට සී සම්පාදකයා විසින් සම්පාදනය කරන ලද ශ්‍රිතයක් ඇති බවයි. එය සී සම්පාදකයා විසින් සම්පාදනය කළ බව ඔබ පැවසීමෙන් පසු, සී ++ සම්පාදකයා එය නිවැරදිව අමතන්නේ කෙසේදැයි දැන ගනු ඇත.

එය C ++ සම්පාදකයාට C ++ ශ්‍රිතයක් සම්පාදනය කිරීමට ඉඩ සලසයි. එම ශ්‍රිතය නිල වශයෙන් C ශ්‍රිතයක් වනු ඇත, නමුත් එය C ++ සම්පාදකයා විසින් සම්පාදනය කර ඇති බැවින්, එයට සියලු C ++ විශේෂාංග භාවිතා කළ හැකි අතර සියලු C ++ මූල පද ඇත.


C ++ සම්පාදකයාට extern "C"ශ්‍රිතයක් සම්පාදනය කළ හැකිය - සහ (සමහර සීමාවන්ට යටත්ව) එය C සම්පාදකයෙකු විසින් සම්පාදනය කරන ලද කේතයෙන් කැඳවිය හැක.
ජොනතන් ලෙෆ්ලර්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.