문제

퍼팅이 정확히 무엇인가요? extern "C" C++ 코드로 들어가나요?

예를 들어:

extern "C" {
   void foo();
}
도움이 되었습니까?

해결책

extern "C"는 C++의 함수 이름에 'C' 연결을 갖도록 만들어서(컴파일러는 이름을 변경하지 않음) 클라이언트 C 코드가 다음을 포함하는 'C' 호환 헤더 파일을 사용하여 함수에 연결(즉, 사용)할 수 있도록 합니다. 귀하의 기능 선언.함수 정의는 클라이언트 'C' 링커가 'C' 이름을 사용하여 연결하는 이진 형식(C++ 컴파일러로 컴파일됨)에 포함되어 있습니다.

C++에는 함수 이름이 오버로드되어 있지만 C에는 그렇지 않기 때문에 C++ 컴파일러는 함수 이름을 링크할 고유 ID로 사용할 수 없으므로 인수에 대한 정보를 추가하여 이름을 엉망으로 만듭니다.C에서는 함수 이름을 오버로드할 수 없으므로 C 컴파일러는 이름을 조작할 필요가 없습니다.C++에서 함수에 extern "C" 연결이 있다고 명시하면 C++ 컴파일러는 연결에 사용되는 이름에 인수/매개변수 유형 정보를 추가하지 않습니다.

아시다시피, 각 개별 선언/정의에 "C" 연결을 명시적으로 지정하거나 블록을 사용하여 일련의 선언/정의를 그룹화하여 특정 연결을 가질 수 있습니다.

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

기술적인 사항에 관심이 있는 경우 C++03 표준의 섹션 7.5에 나열되어 있습니다. 다음은 간단한 요약입니다(extern "C"에 중점을 두고).

  • extern "C"는 연결 사양입니다.
  • 모든 컴파일러는 필수의 "C" 링크 제공
  • 연결 사양은 네임스페이스 범위에서만 발생해야 합니다.
  • 모든 함수 유형, 함수 이름 및 변수 이름에는 언어 연결이 있습니다. Richard의 의견을 참조하세요. 외부 연결이 있는 함수 이름과 변수 이름만 언어 연결이 있습니다.
  • 서로 다른 언어 연결이 있는 두 함수 유형은 다른 점은 동일하더라도 서로 다른 유형입니다.
  • 연결 사양 중첩, 내부 사양이 최종 연결을 결정합니다.
  • 클래스 멤버에 대해서는 extern "C"가 무시됩니다.
  • 특정 이름을 가진 최대 하나의 함수는 "C" 링크를 가질 수 있습니다(네임스페이스에 관계없이).
  • extern "C"는 함수가 외부 연결을 갖도록 강제합니다(정적으로 만들 수 없음). Richard의 의견을 참조하십시오. 'extern "C"' 내부의 '정적'은 유효합니다.이렇게 선언된 엔터티에는 내부 연결이 있으므로 언어 ​​연결이 없습니다.
  • C++에서 다른 언어로 정의된 개체로, 다른 언어에서 C++로 정의된 개체로 연결하는 것은 구현에 따라 정의되며 언어에 따라 다릅니다.두 언어 구현의 객체 레이아웃 전략이 충분히 유사한 경우에만 그러한 연결이 달성될 수 있습니다.

다른 팁

아직 게시 한 것을 보지 못했기 때문에 약간의 정보를 추가하고 싶었습니다.

당신은 종종 C 헤더에서 코드를 볼 수 있습니다.

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

이를 달성하는 것은 매크로 "__cplusplus"가 정의되기 때문에 C ++ 코드와 함께 해당 C 헤더 파일을 사용할 수 있다는 것입니다. 하지만 당신은 할 수 있습니다 또한 매크로가있는 레거시 C 코드와 함께 사용하십시오. 아니다 정의되어 있으므로 고유 한 C ++ 구성이 표시되지 않습니다.

비록 다음과 같은 C ++ 코드도 보았습니다.

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

내가 상상하는 것은 거의 같은 것을 성취한다고 생각합니다.

어떤 방법이 더 나은지 잘 모르겠지만 두 가지를 모두 보았습니다.

모든 C ++ 프로그램에서 모든 비 정적 함수는 이진 파일에 기호로 표시됩니다. 이 기호는 프로그램의 함수를 고유하게 식별하는 특수 텍스트 문자열입니다.

C에서 기호 이름은 함수 이름과 동일합니다. C에서는 두 개의 비 정적 함수가 동일한 이름을 가질 수 없기 때문에 가능합니다.

C ++는 과부하를 허용하고 Class, 멤버 함수, 예외 사양과 같이 C가없는 많은 기능이 있기 때문에 기능 이름을 기호 이름으로 간단히 사용할 수는 없습니다. 이를 해결하기 위해 C ++는 소위 이름 Mangling을 사용합니다.이 이름은 기능 이름과 필요한 모든 정보 (인수의 숫자와 크기와 같은)를 컴파일러와 링커에서만 처리 한 이상한 문자열로 변환합니다.

따라서 외부 C로 함수를 지정하면 컴파일러가 이름을 angling으로 수행하지 않으며 기호 이름을 함수 이름으로 사용하여 직접 액세스 할 수 있습니다.

이것은 사용하는 동안 편리합니다 dlsym() 그리고 dlopen() 그러한 기능을 호출합니다.

소집 a 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(); }

GCC 4.8 Linux로 컴파일하십시오 꼬마 요정 산출:

g++ -c main.cpp

기호 테이블을 디 컴파일 :

readelf -s main.o

출력에는 다음이 포함됩니다.

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

해석

우리는 그것을 본다 :

  • ef 그리고 eg 코드와 동일한 이름의 기호로 저장되었습니다.

  • 다른 상징은 엉망이되었습니다. 그들을 풀자 :

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

결론 : 다음 두 기호 유형은 두 가지 모두였습니다 ~ 아니다 엉망진 사람 :

  • 한정된
  • 선언되었지만 정의되지 않은 (Ndx = UND), 다른 개체 파일에서 링크 또는 실행 시간에 제공됩니다.

그래서 당신은 필요합니다 extern "C" 둘 다 전화 할 때 :

  • C ++에서 C : Tell g++ 불안정한 상징이 생성 된 기호를 기대합니다 gcc
  • C에서 C ++ : Tell g++ 정지되지 않은 기호를 생성합니다 gcc 사용

외부에서 작동하지 않는 것 c

이름 Mangling이 필요한 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

완전성과 Newbs를 위해 다음을 참조하십시오. 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++. */
#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++ 망가진을 찾을 것으로 예상됩니다 f, 어느 gcc 생산하지 않았습니다.

Github의 예.

C 예에서 최소 실행 가능한 C ++

C에서 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에서 테스트.

C++는 함수 이름을 조작하여 절차적 언어에서 객체 지향 언어를 만듭니다.

대부분의 프로그래밍 언어는 기존 프로그래밍 언어 위에 구축되지 않습니다.C++는 C 위에 구축되었으며, 더 나아가 절차적 프로그래밍 언어를 기반으로 구축된 객체 지향 프로그래밍 언어이므로 다음과 같은 C++ 표현식이 있습니다. extern "C" 이는 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;
}

C 컴파일러는 위의 예를 컴파일하지 않습니다. printMe 두 번 정의되었습니다(다른 매개변수를 갖고 있음에도 불구하고). int achar a).

gcc -o printMe printMe.c && ./printMe;
오류가 1개 있습니다.PrintMe가 두 번 이상 정의되었습니다.

C++ 컴파일러는 위의 예제를 컴파일합니다.그런건 상관없어 printMe 두 번 정의됩니다.

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

이는 C++ 컴파일러가 암시적으로 (망글)는 해당 매개변수를 기반으로 기능합니다.C에서는 이 기능이 지원되지 않았습니다.그러나 C++를 C 위에 구축할 때 언어는 객체 지향적으로 설계되었으며, 동일한 이름의 메서드(함수)로 다른 클래스를 생성하고 메서드를 재정의하는 기능(메서드 재정의) 다양한 매개변수를 기반으로 합니다.

extern "C" "C 함수 이름을 엉망으로 만들지 마세요"라고 말합니다.

그러나 "parent.c"라는 레거시 C 파일이 있다고 가정해 보겠습니다. include다른 레거시 C 파일의 함수 이름("parent.h", "child.h" 등)레거시 "parent.c" 파일이 C++ 컴파일러를 통해 실행되면 함수 이름이 손상되어 "parent.h", "child.h" 등에 지정된 함수 이름과 더 이상 일치하지 않게 됩니다. 해당 외부 파일의 함수 이름도 수정해야 합니다.종속성이 많은 복잡한 C 프로그램에서 함수 이름을 변경하면 코드가 깨질 수 있습니다.따라서 C++ 컴파일러에게 함수 이름을 엉망으로 만들지 않도록 지시할 수 있는 키워드를 제공하는 것이 편리할 수 있습니다.

그만큼 extern "C" 키워드는 C++ 컴파일러에게 C 함수 이름을 변경(이름 변경)하지 말라고 지시합니다.사용 예: extern "C" void printMe(int a);

함수가 C에서 호출 할 수있는 방식으로 함수의 연결을 변경합니다. 실제로 함수 이름이 아닙니다. 엉망이되었습니다.

외부 "C"로 단순히 포장하여 C-Header가 C ++와 호환 될 수는 없습니다. C-Header의 식별자가 C ++ 키워드와 충돌하면 C ++ 컴파일러가 이에 대해 불평합니다.

예를 들어 G ++에서 다음 코드가 실패했습니다.

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

Kinda는 의미가 있지만 C 코드를 C ++로 포팅 할 때 명심해야 할 사항입니다.

C 및 C ++에서 컴파일 된 함수의 이름은 연결 스테이지에서 다르기 때문에 C ++ 컴파일러가 C 스타일로 해당 함수의 이름을 조회하도록 알려줍니다.

Extern "C"는 C ++ 컴파일러에 의해 인식되고 Compiler에 명시된 함수가 C 스타일로 컴파일 된 것을 알리기위한 것입니다. 링크하는 동안 C에서 올바른 기능의 함수 버전으로 연결됩니다.

DLL (Dynamic Link Library) 파일에 대해 'extern "C"를 사용하여 Main () 함수 "내보낼 수있는"기능을 사용하므로 나중에 DLL의 다른 실행 파일에서 사용할 수 있습니다. 어쩌면 내가 사용했던 곳의 예는 유용 할 수 있습니다.

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

extern "C" 익숙한 연결 사양입니다 C 기능을 호출하십시오 에서 CPP 소스 파일. 우리는 할 수 있습니다 C 함수 호출, 변수 쓰기 및 헤더 포함. 함수는 외부 엔티티에서 선언되며 외부에서 정의됩니다. 구문입니다

Type 1:

extern "language" function-prototype

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

이 답변은 참을성이없는/ 마감일이 만나는 것입니다. 부품/ 간단한 설명 만 다음과 같습니다.

  • C ++에서는 오버로드를 통해 클래스에서 동일한 이름을 가질 수 있습니다 (예 : 모두 동일한 이름이 DLL에서 as-as-Is-Is 등을 내보낼 수 없기 때문에이 문제에 대한 솔루션은 다른 문자열로 변환된다는 것입니다 (기호라고합니다. ), 기호는 함수의 이름, 인수도 설명하므로 동일한 이름으로도 이러한 함수를 고유하게 식별 할 수 있습니다 (또한 이름 Mangling).
  • C에서는 오버로드가없고 함수 이름은 고유합니다 (따라서 기능 이름을 고유하게 식별하기위한 별도의 문자열은 필요하지 않으므로 기호는 함수 이름 자체입니다).

그래서
C ++에서 이름을 독창적 인 Identities 각 기능으로
C에서, 이름이 없어도 독창적 인 정체성 각 기능

C ++의 동작을 변경하려면, 즉 이름 Mangling을 지정합니다. 해서는 안됩니다 특정 함수에 대해 발생하면 사용할 수 있습니다 extern "c" 함수 이름 앞에 클라이언트가 사용하기 위해 DLL에서 특정 이름으로 함수를 내보내는 등 어떤 이유로 든

자세한 내용/더 정답은 다른 답변을 읽으십시오.

C와 C ++를 혼합 할 때 (예 : C ++에서 C 함수를 호출하고 b. c에서 c ++ 함수를 호출) C ++ 이름 Mangling은 문제를 연결합니다. 기술적으로 말하면,이 문제는 Callee 함수가 해당 컴파일러를 사용하여 이미 이진 (아마도 A *.A 라이브러리 파일)으로 컴파일 된 경우에만 발생합니다.

따라서 C ++에서 Mangling이라는 이름을 비활성화하려면 Extern "C"를 사용해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top