간단히 말하면 extern "C"는 C++에서 C와의 호환성을 위해 C 언어 기호를 선언하거나 정의하는 방법입니다. 말하기는 쉽지만 이해하는 데에는 여전히 약간의 어려움이 있습니다. 먼저 C++와 C의 차이점부터 시작해야 합니다.
기호
우리 모두 알고 있듯이 코드에서 실행 가능한 프로그램까지 컴파일과 링크라는 두 가지 과정을 거쳐야 합니다. 컴파일 단계에서는 구문 감지와 코드 확장이 이루어집니다. 또한 변수를 기호로 변환하는 작업도 수행합니다. 연결 시 실제로 기호를 통해 위치를 찾습니다. 컴파일러가 C 및 C++ 코드를 컴파일할 때 변수를 기호로 변환하는 프로세스가 다릅니다. 이번 글에서 사용한 컴파일러는 gcc4.4.7입니다
먼저 간단한 코드를 살펴보겠습니다
/* hello.c */ #include <stdio.h> const char* g_prefix = "hello "; void hello(const char* name) { printf("%s%s", g_prefix, name); }
여기서 파일명은 hello.c이므로 컴파일 gcc -c를 실행합니다. hello.c는 대상 파일 hello.o를 가져옵니다. nm을 사용하여 Linux에서 대상 파일의 기호 테이블을 확인하고 다음과 같은 결과를 얻습니다($ 기호는 셸 명령 프롬프트를 나타냄)
$ nm hello.o 0000000000000000 D g_prefix 0000000000000000 T hello U printf
이것은 C 코드가 컴파일된 후의 기호 목록에서 세 번째 열은 컴파일된 기호 이름입니다. 우리는 주로 자체 정의한 전역 변수 g_prefix 및 함수 hello를 살펴봅니다. hello.c의 이름을 hello.cpp로 바꾸고 gcc -c hello.cpp를 다시 컴파일하여 hello.o를 얻은 다음 nm로 봅니다.
0000000000000000 T _Z5helloPKc U __gxx_personality_v0 0000000000000000 D g_prefix U printf
다음은 기호 목록입니다. C++ 코드가 컴파일되면 gcc는 파일 접미사 이름을 기반으로 C 및 C++ 코드를 자동으로 식별합니다. 이때 g_prefix의 기호는 변경되지 않았지만 hello 함수의 기호가 _Z5helloPKc로 변경되었음을 알 수 있습니다. C 및 C++ 코드를 컴파일할 때 gcc의 처리 방법은 다릅니다. C 코드의 경우 변수의 기호 이름은 변수 자체입니다(초기에는 컴파일러에서 C 코드 변수 앞에 밑줄 _을 추가했지만 지금은 기본적으로는 그렇게 하지 않습니다. 컴파일 중에 컴파일 옵션 -fno-leading-underscore 및 -fleading-underscore를 전달하여 명시적으로 설정할 수 있습니다. C++ 코드의 경우 데이터 변수이고 중첩이 없으면 기호 이름은 그 자체이며, 변수 이름이 중첩되거나(네임스페이스 또는 클래스에서) 함수 이름인 경우 기호 이름은 다음 규칙에 따라 처리됩니다.
1. 기호는 _Z로 시작합니다.
2. 중첩이 있는 경우 N 다음에 이름 공간, 이름 앞의 숫자는 길이입니다. E
3. 중첩이 없을 경우 바로 이름의 길이입니다
4. 마지막으로 타입과 기호의 대응관계는 다음과 같습니다
int -> i float -> f double -> d char -> c void -> v const -> K * -> P
이를 통해 C++ 코드의 void hello(const char*)에 컴파일 후 _Z5helloPKc 기호가 있는 이유를 쉽게 이해할 수 있습니다(PKc는 오른쪽에서 왼쪽으로 char const * 유형으로 변환됩니다. 이는 내부 컴파일러의 표현, 우리가 사용하는 표현은 const char*이며 둘은 동일합니다.) c++filt 도구는 기호에서 이름을 추론할 수 있으며 사용 방법은 c++filt _Z5helloPKc
C++에서는 함수 오버로딩을 지원하지만 C에서는 지원하지 않는 이유도 이해하기 쉽습니다. 왜냐하면 C++에서는 함수를 기호로 수정할 때 함수의 매개변수 유형을 추가하지만 C에서는 그렇지 않기 때문입니다. 매개변수가 다른 경우에는 기호 이름이 충돌하지 않는 한 동일합니다. 다음 예를 통해 변수 이름과 기호 간의 관계를 확인할 수 있습니다./ * filename : test.cpp */ #include <stdio.h> namespace myname { int var = 42; } extern int _ZN6myname3varE; int main() { printf("%d\n", _ZN6myname3varE); return 0; }여기서는 네임스페이스에 전역 변수 var를 정의합니다. 이전 내용에 따르면 _ZN6myname3varE 기호로 수정한 다음 외부 변수 _ZN6myname3varE를 수동으로 선언하고 인쇄합니다. 컴파일하고 실행해 보면 그 값은 정확히 var
$ gcc test.cpp -o test -lstdc++ $ ./test 42extern "C"기호의 개념으로 extern "의 사용법을 쉽게 살펴볼 수 있습니다. C"
extern "C" { int func(int); int var; }이것은 컴파일러에게 extern "C" 다음에 대괄호 안의 코드를 C 코드로 처리하라고 지시하는 것을 의미합니다. 물론
extern "C" int func(int); extern "C" int var;을 선언할 수도 있습니다. 단일 문 이는 C 유형의 func 및 var를 선언합니다. 우리는 C 언어 함수를 선언하기 위해 헤더 파일을 작성하는 경우가 많으며, 이러한 함수는 C 및 C++ 코드에서 호출될 수 있습니다. C++ 코드에서 호출할 때는 헤더 파일에 extern "C"를 추가해야 합니다. 그렇지 않으면 C++에서는 컴파일 기호를 찾을 수 없으며 C 코드를 호출할 때 extern "C"를 추가할 수 없습니다. C가 이러한 구문을 지원하지 않기 때문입니다. 이를 처리하는 일반적인 방법은 다음과 같습니다. 🎜> 그 중 __cplusplus는 C++ 컴파일러에서 정의한 매크로입니다. 이 코드를 C++로 컴파일하면 memset이 C 코드로 컴파일되면 선언됩니다. __cplusplus가 정의되지 않았으므로 구문 오류가 없습니다. 이 기술은 시스템 헤더 파일에 자주 사용됩니다.
#ifdef __cplusplus extern "C" { #endif void *memset(void*, int, size_t); #ifdef __cplusplus } #endif
C++에서 extern "C" 사용법에 대한 자세한 설명과 관련 글은 PHP 중국어 홈페이지를 참고해주세요!