C ++에서 extern“C”의 효과는 무엇입니까?


1632

extern "C"C ++ 코드에 정확히 들어가는 것은 무엇입니까 ?

예를 들면 다음과 같습니다.

extern "C" {
   void foo();
}

82
이 기사를 소개하고 싶습니다 : http://www.agner.org/optimize/calling_conventions.pdf 그것은 호출 규칙과 컴파일러의 차이점에 대해 훨씬 더 많이 알려줍니다.
Sam Liao

1
@Litherum 내 머리 위에는 크로스 컴파일러가 있다고 가정하면 C를 사용하여 해당 코드 범위를 컴파일하도록 컴파일러에 지시합니다. 또한 해당 foo()기능 이있는 Cpp 파일이 있음을 의미 합니다.
ha9u63ar

1
@ ha9u63ar 그것은 내 머리 꼭대기에서 벗어났다. 귀하의 의견 전체가 잘못되었습니다. 삭제하는 것이 좋습니다.
TamaMcGlinn

답변:


1558

extern "C"는 C ++에서 function-name에 'C'연결 (컴파일러가 이름을 엉망으로 만들지 않음)을 만들도록하여 클라이언트 C 코드가 함수 선언. 함수 정의는 클라이언트 'C'링커가 'C'이름을 사용하여 연결할 바이너리 형식 (C ++ 컴파일러에서 컴파일 한)으로 포함됩니다.

C ++에는 함수 이름이 오버로드되고 C는 그렇지 않으므로 C ++ 컴파일러는 함수 이름을 링크 할 고유 ID로 사용할 수 없으므로 인수에 대한 정보를 추가하여 이름을 엉망으로 만듭니다. C에서 함수 이름을 오버로드 할 수 없으므로 AC 컴파일러는 이름을 맹 글링 할 필요가 없습니다. 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"'내의 'static'은 유효합니다. 이렇게 선언 된 엔터티에는 내부 연결이 있으므로 언어 ​​연결이 없습니다.
  • C ++에서 다른 언어로 정의 된 객체 및 다른 언어에서 C ++로 정의 된 객체로의 연결은 구현 정의 및 언어에 따라 다릅니다. 두 언어 구현의 객체 레이아웃 전략이 유사한 경우에만 그러한 연결을 달성 할 수 있습니다

21
C 컴파일러는 c ++이하는 mangling을 사용하지 않습니다. 따라서 C ++ 프로그램에서 ac 인터페이스를 호출하려면 c 인터페이스를 "extern c"로 명확하게 선언해야합니다.
Sam Liao

58
@Faisal : 상호 참조가 모두 'extern "C"인 경우에도 다른 C ++ 컴파일러로 빌드 된 코드를 연결하지 마십시오. 클래스의 레이아웃이나 예외 처리에 사용되는 메커니즘 또는 사용 전에 변수가 초기화되도록하는 메커니즘 또는 이와 같은 차이점 사이에는 종종 차이가 있으며, 두 개의 개별 C ++ 런타임 지원 라이브러리가 필요합니다 (하나는 각 컴파일러).
Jonathan Leffler

8
'extern "C"는 함수가 외부 링크를 갖도록 강제합니다 (정적화할 수 없음). 'extern "C"'내의 'static'은 유효합니다. 이렇게 선언 된 엔터티에는 내부 연결이 있으며 언어 연결도 없습니다.
Richard Smith

14
'모든 함수 유형, 함수 이름 및 변수 이름에 언어 연결이 있습니다'도 올바르지 않습니다. 외부 연결이있는 함수 이름 및 변수 이름에만 언어 연결이 있습니다.
Richard Smith

9
참고 extern "C" { int i; }정의입니다. 의 비정의 옆에있는 의도 한 것이 아닐 수도 있습니다 void g(char);. 그것을 비정의로 만들려면 필요합니다 extern "C" { extern int i; }. 반면에, 중괄호가없는 한 선언 구문은 선언을 비 정의을 수행합니다 extern "C" int i;과 동일extern "C" { extern int i; }
aschepler

327

정보가 아직 게시되지 않았기 때문에 약간의 정보를 추가하고 싶었습니다.

다음과 같이 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"
}

나는 똑같은 일을 성취한다고 상상합니다.

어느 쪽이 더 좋은지 잘 모르겠지만 둘 다 보았습니다.


11
뚜렷한 차이가 있습니다. 전자의 경우, 일반 gcc 컴파일러로이 파일을 컴파일하면 함수 이름이 엉망이 아닌 객체가 생성됩니다. 그런 다음 C 및 C ++ 객체를 링커와 연결하면 함수를 찾을 수 없습니다. 두 번째 코드 블록에서와 같이 해당 "레거시 헤더"파일을 extern 키워드와 함께 포함해야합니다.
앤 반 로섬

8
@Anne : C ++ 컴파일러는 extern "C"헤더에서 보았으므로 엉킴없는 이름을 찾습니다 . 그것은이 기술을 여러 번 사용하여 훌륭하게 작동합니다.
Ben Voigt 2016 년

20
@Anne : 그렇습니다. 첫 번째도 괜찮습니다. C 컴파일러에서는 무시되며 C ++의 두 번째와 동일한 효과를 갖습니다. 컴파일러 extern "C"는 헤더를 포함하기 전이나 후에 만날 지 신경 쓰지 못했습니다 . 컴파일러에 도달 할 때까지는 전처리 된 텍스트 스트림 중 하나 일뿐입니다.
Ben Voigt 2016 년

8
@Anne, 아니요, 설명하는 내용이 잘못 되었기 때문에 소스의 다른 오류로 영향을 받았다고 생각합니다. g++지난 17 년 중 언제라도 어느 버전 에서든 어떤 버전의 버전 에서도이 문제가 발생하지 않았습니다. 첫 번째 예제의 요점은 C 또는 C ++ 컴파일러를 사용하는지 여부는 중요하지 않으며 extern "C"블록 의 이름에 대해서는 이름 변환이 수행되지 않는다는 것 입니다.
Jonathan Wakely

7
"어느 쪽이 더 낫다"-첫 번째 변형이 더 낫다. C와 C ++ 코드 모두에서 추가 요구 사항없이 헤더를 직접 포함 할 수있다. 두 번째 접근 방식은 작성자가 C ++ 가드를 잊어 버린 C 헤더의 해결 방법입니다 (문제는 없지만 나중에 추가하면 중첩 된 extern "C"선언이 허용됩니다 ...).
Aconcagua

267

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

해석

우리는 그것을 본다 :

  • efeg코드에서와 동일한 이름을 가진 심볼에 저장된

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

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

결론 : 다음 두 심볼 유형 모두 엉망 이 되지 않았습니다 .

  • 한정된
  • Ndx = UND다른 객체 파일에서 링크 또는 런타임에 제공되도록 선언되었지만 정의되지 않음 ( )

따라서 extern "C"전화를 걸 때 둘 다 필요 합니다.

  • C에서 C ++ : 말씀 g++에 의해 생산 unmangled 문자 기대gcc
  • C의 C ++ : 사용할 g++엉킴없는 심볼을 생성 gcc하도록 지시

extern 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를 호출하는 것은 매우 쉽습니다. 각 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++예상하는 찾을 난도질 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.


21
우수 답변 당신은 1) 명시 적으로 언급하기 때문에 extern "C" {당신이 전화를하는 데 도움이 C ++ 프로그램 내에서 unmangled C의 기능을 뿐만 아니라, C 프로그램 내에서 기능 ++ unmangled C 다른 답변은 그리 명확하지 않습니다, 그리고 당신의 별개의 예를 보여 있기 때문에) 2 마다. 감사!
Gabriel Staples

3
나는이 답변을 매우 좋아합니다
selfboot

4
c에서 오버로드 된 함수를 호출하는 방법을 보여
주므로

1
@JaveneCPPMcGowan C ++ 선생님이 있다고 생각하는 이유는 무엇입니까? :-)
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

205

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

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

C ++은 오버로딩을 허용하고 클래스, 멤버 함수, 예외 사양과 같이 C가 지원하지 않는 많은 기능을 가지고 있기 때문에 단순히 함수 이름을 기호 이름으로 사용할 수 없습니다. 이를 해결하기 위해 C ++은 함수 이름과 필요한 모든 정보 (인수의 수 및 크기 등)를 컴파일러와 링커에서만 처리하는 이상한 문자열로 변환하는 이른바 이름 관리 (name mangling)를 사용합니다.

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

이러한 기능 을 사용 dlsym()하고 dlopen()호출 할 때 편리 합니다.


핸디 란 무엇을 의미합니까? 기호 이름 = 함수 이름은 기호 이름을 dlsym에 전달합니까, 아니면 다른 것입니까?
오류

1
@ 오류 : 예. 일반적으로 헤더 파일 만 제공된 C ++ 공유 라이브러리를 dlopen ()하고로드 할 올바른 함수를 선택하는 것은 본질적으로 불가능합니다. (x86에는 Itanium ABI 형식으로 출판 된 이름-매 글링 사양이 있는데, 이것이 내가 아는 모든 x86 컴파일러가 C ++ 함수 이름을 맹 글링하는 데 사용하는 것으로 알고 있지만, 언어로는 아무것도 필요하지 않습니다.)
Jonathan Tomer

52

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

AC 컴파일러는 동일한 함수 printMe가 두 번 정의되어 있기 때문에 위의 예제를 컴파일하지 않습니다 (파라미터 int a와 매개 변수가 다르더라도 char a).

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

C ++ 컴파일러는 위 예제를 컴파일합니다. printMe두 번 정의 된 것은 중요하지 않습니다 .

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

이는 C ++ 컴파일러 가 매개 변수에 따라 함수의 이름을 암시 적으로 변경 ( mangles ) 하기 때문 입니다. C에서는이 기능이 지원되지 않았습니다. 그러나 C ++가 C를 기반으로 구축 된 경우 언어는 객체 지향으로 설계되었으며 동일한 이름의 메소드 (함수)를 사용하여 다른 클래스를 작성하고,이를 기반으로 메소드 ( 메소드 대체 ) 를 대체하는 기능을 지원해야했습니다. 매개 변수.

extern "C" "C 함수 이름을 맹 글링하지 마십시오"

그러나 include다른 레거시 C 파일 "parent.h", "child.h"등의 함수 이름 인 "parent.c"라는 레거시 C 파일이 있다고 가정합니다. 레거시 "parent.c"파일이 실행되는 경우 C ++ 컴파일러를 통해 함수 이름이 엉망이되어 더 이상 "parent.h", "child.h"등에 지정된 함수 이름과 일치하지 않으므로 외부 파일의 함수 이름도 엉망이다 의존성이 많은 복잡한 C 프로그램에서 함수 이름을 다루면 코드가 깨질 수 있습니다. 따라서 C ++ 컴파일러에게 함수 이름을 맹 글링하지 않도록 지시 할 수있는 키워드를 제공하는 것이 편리 할 수 ​​있습니다.

extern "C"키워드는에 압착 롤러 (이름 바꾸기) C 함수 이름은 C ++ 컴파일러를 알려줍니다.

예를 들면 다음과 같습니다.

extern "C" void printMe(int a);


파일 extern "C"만 있으면 사용할 수 dll없습니까? 헤더 파일이없고 소스 파일 (구현 만)이 있고 함수 포인터를 통해 그 기능을 사용한다면 의미합니다. 이 상태에서는 이름에 관계없이 함수를 사용했습니다.
BattleTest에서

@ tfmontague, 나를 위해 당신은 그것을 올바르게 못 박았습니다! 머리에 똑바로.
Artanis Zeratul

29

extern "C"로 감싸서 C 헤더를 C ++과 호환되도록 만들 수는 없습니다. C- 헤더의 식별자가 C ++ 키워드와 충돌하면 C ++ 컴파일러는 이에 대해 불평합니다.

예를 들어, g ++에서 다음 코드가 실패하는 것을 보았습니다.

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

Kinda는 의미가 있지만 C 코드를 C ++로 이식 할 때 명심해야합니다.


14
extern "C"다른 답변에서 설명한대로 C 연결을 사용하는 것을 의미합니다. "내용을 C로 컴파일"또는 다른 것을 의미하는 것은 아닙니다. int virtual;C ++에서는 유효하지 않으며 다른 연결을 지정해도 변경되지 않습니다.
MM

1
... 또는 모드는 일반적으로 구문 오류가 포함 된 코드가 컴파일되지 않습니다.
Valentin Heinitz

4
@ValentinHeinitz는 자연스럽게 C에서 식별자로 "가상"을 사용하는 것은 구문 오류가 아닙니다. 난 그냥 지점 싶어 당신 수 없습니다 자동으로 사용할 수 있는 C 헤더 C ++ 주위 통근 "C"를 넣어.
Sander Mertens

28

C에서 함수를 호출 할 수있는 방식으로 함수의 링크를 변경합니다. 실제로 함수 이름이 엉망 이되지 않습니다 .


3
얽힌 용어는 일반적으로 사용되는 용어입니다. 제가이 의미로 '장식 된'장식을 본 적이 있다고 믿지 마십시오.
Matthew Scharley

1
Microsoft는 (적어도 부분적으로) 설명서에 엉망이 아닌 장식을 사용 합니다. 심지어 이름을 꾸미지 않기 위해 도구의 이름을 지정하기도 undname합니다.
René Nyffenegger

20

C와 C ++로 컴파일 된 함수의 이름이 연결 단계에서 다르기 때문에 C ++ 컴파일러는 링크 할 때 C 스타일에서 해당 함수의 이름을 찾도록 지시합니다.


12

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


6

이전에 dll (dynamic link library) 파일에 대해 'extern "C"를 사용하여 main () 함수를 "exportable"로 만들었으므로 나중에 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);
}

4
가짜. extern "C"__declspec(dllexport)관련이 없습니다. 전자는 심볼 장식을 제어하고 후자는 내보내기 항목을 생성합니다. C ++ 이름 데코레이션을 사용하여 심볼을 내보낼 수도 있습니다. 이 질문의 요점을 완전히 잃어버린 것 외에도 코드 샘플에는 다른 실수도 있습니다. 하나 main는 DLL에서 내 보낸 값을 반환하지 않습니다. 또는 그 문제에 대한 전화 회의. 가져올 때 임의 호출 규칙 ( WINAPI)의 속성을 지정하고 32 비트 빌드 ( _main또는 이어야 함 _main@0)에 잘못된 기호를 사용합니다 . 죄송합니다, -1
IInspectable

1
반복되는 것, 당신이 모르는 것, 당신이하는 일, 그러나이 방법을 사용하는 것은 공개되지 않은 대상 플랫폼 목록에 대해 당신에게 효과가있는 것으로 보입니다. 이전 의견에서 제기 한 문제는 다루지 않았습니다. 이것은 여전히 ​​엉뚱하기 때문에 여전히 투표권이 있습니다 (더 많은 것은 단일 의견에 맞지 않습니다).
IInspectable

1
스택 오버플로에 대한 답변을 게시하면 자신이하는 일을 알 수 있습니다. 이것은 예상됩니다. "실행시 스택 손상 방지" 시도에 대해 : 함수 시그니처는 type의 리턴 값을 지정 void*하지만 구현은 아무것도 리턴하지 않습니다. 정말 잘 날 것입니다 ...
IInspectable

1
운이 좋게 작동 하는 것처럼 보이는 것을 구현 하면 현재하고있는 일 을 명확하게 알 수 없습니다 ( "작업" 샘플이 해당 범주에 속함). 정의되지 않은 동작이며 작동하는 것처럼 보이는 것은 정의되지 않은 동작의 올바른 형태입니다. 아직 정의되지 않았습니다. 앞으로 더 많은 노력을 기울이면 대단히 감사하겠습니다. 그중 일부는이 제안 된 답변을 삭제했을 수 있습니다.
IInspectable

1
포인터를 반환하는 함수로 아무것도 반환하지 않는 함수를 재 해석하고 있습니다. x86이 불일치 함수 시그니처, 특히 정수 유형의 반환 값과 관련하여 매우 용서한다는 것은 행운입니다. 코드는 우연히 만 작동합니다. 동의하지 않으면 코드가 안정적으로 작동하는 이유를 설명해야합니다.
IInspectable

5

extern "C"Cpp 소스 파일 에서 C 함수호출 하는 데 사용되는 연결 사양입니다 . C 함수호출하고 변수를 작성하며 헤더를 포함 할 수 있습니다 . 함수는 extern entity에 선언되어 있으며 외부에 정의되어 있습니다. 구문은

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

3

이 답변은 참을성이없는 / 마감일을 맞추기위한 것이며 일부 / 간단한 설명 만 아래에 있습니다.

  • C ++에서는 오버로드를 통해 클래스에서 동일한 이름을 가질 수 있습니다 (예 : dll 등에서 그대로 이름을 내보낼 수 없으므로).이 문제에 대한 해결책은 다른 문자열 (심볼이라고 함)로 변환됩니다 )에서 기호는 함수의 이름과 인수를 설명하므로 동일한 이름을 가진 각 함수를 고유하게 식별 할 수 있습니다 (이름 맹 글링이라고도 함).
  • C에서는 오버로드가 없으며 함수 이름이 고유합니다 (따라서 함수 이름을 고유하게 식별하기위한 별도의 문자열이 필요하지 않으므로 symbol은 함수 이름 자체입니다)

따라서
C ++에서는 이름을 고유하게 식별하여 각 함수
를 고유하게 식별합니다.

C ++의 동작을 변경하려면, 즉 특정 함수에 대해 이름 변환 발생 하지 않도록 지정 하려면 dll에서 특정 이름을 가진 함수를 내보내는 등 어떤 이유로 든 함수 이름 앞에 extern "C" 를 사용할 수 있습니다. 클라이언트가 사용합니다.

더 자세하고 정확한 답변을 얻으려면 다른 답변을 읽으십시오.


1

C와 C ++를 혼합 할 때 (즉, a. C ++에서 C 함수 호출, b. C에서 C ++ 함수 호출) C ++ 이름 맹 글링은 연결 문제를 일으 킵니다. 기술적으로 말하면,이 문제는 수신자 함수가 해당 컴파일러를 사용하여 바이너리 (대부분 * .a 라이브러리 파일)로 이미 컴파일 된 경우에만 발생합니다.

따라서 extern "C"를 사용하여 C ++에서 이름 맹 글링을 비활성화해야합니다.


0

다른 좋은 대답과 충돌하지 않고 약간의 예를 추가하겠습니다.

정확히 C ++ 컴파일러의 기능 : 컴파일 프로세스에서 이름을 엉망으로 만들므로 컴파일러에게 구현을 특별히 처리 하도록 지시해야합니다 C.

C ++ 클래스를 만들고를 추가 할 때 extern "C"C ++ 컴파일러에 C 호출 규칙을 사용하고 있다고 알려줍니다.

이유 (우리는 C ++에서 C 구현을 호출합니다) : C ++에서 C 함수를 호출하거나 C에서 C ++ 함수를 호출하려고합니다 (C ++ 클래스 ... 등은 C에서 작동하지 않음).


스택 오버플로에 오신 것을 환영합니다. 잘 정립되고 정답이있는 오래된 질문에 대답하기로 결정한 경우, 늦은 시간에 새 답변을 추가하면 크레딧을 얻지 못할 수 있습니다. 독특한 새로운 정보가 있거나 다른 답변이 모두 잘못되었다고 확신하는 경우 반드시 새로운 답변을 추가하되, 질문이 일반적으로 제기 된 후 오랫동안 동일한 기본 정보를 제공하는 '아직 다른 답변'을 작성하십시오. ' 당신은 많은 신용을 얻습니다. 솔직히, 나는이 대답에 새로운 것이 없다고 생각합니다.
Jonathan Leffler

글쎄, 난 당신의 요점을 기억해야합니다-좋아
Susobhan Das

-1

C 컴파일러에 의해 컴파일 된 void f () 함수와 C ++ 컴파일러에 의해 컴파일 된 void f () 같은 이름의 함수는 동일한 함수가 아닙니다. C로 해당 함수를 작성하고 C ++에서 호출하려고하면 링커가 C ++ 함수를 찾고 C 함수를 찾지 않습니다.

extern "C"는 C ++ 컴파일러에게 C 컴파일러에 의해 컴파일 된 함수가 있음을 알려줍니다. C 컴파일러에 의해 컴파일되었다고 말하면 C ++ 컴파일러는이를 올바르게 호출하는 방법을 알게됩니다.

또한 C ++ 컴파일러가 C 컴파일러가 호출 할 수있는 방식으로 C ++ 함수를 컴파일 할 수 있습니다. 이 함수는 공식적으로 C 함수이지만 C ++ 컴파일러에 의해 컴파일되므로 모든 C ++ 기능을 사용할 수 있으며 모든 C ++ 키워드가 있습니다.


C ++ 컴파일러는 extern "C"함수를 컴파일 할 수 있으며 C 컴파일러가 컴파일 한 코드로 호출 할 수 있습니다 (일부 제약 조건에 따라 다름).
Jonathan Leffler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.