extern "C"
를 C++ 코드에 넣는 것은 정확히 무엇을 합니까?
예를 들어:
extern "C" { void foo(); }
질문자 :Litherum
extern "C"
를 C++ 코드에 넣는 것은 정확히 무엇을 합니까?
예를 들어:
extern "C" { void foo(); }
extern "C"
는 C++의 함수 이름에 C 연결(컴파일러는 이름을 맹글링하지 않음)을 만들어 클라이언트 C 코드가 함수 선언만 포함하는 C 호환 헤더 파일을 사용하여 함수에 연결할 수 있도록 합니다. 함수 정의는 클라이언트 C 링커가 C 이름을 사용하여 연결할 바이너리 형식(C++ 컴파일러로 컴파일됨)에 포함되어 있습니다.
C++에는 함수 이름의 오버로딩이 있고 C는 그렇지 않기 때문에 C++ 컴파일러는 함수 이름을 링크할 고유 ID로 사용할 수 없으므로 인수에 대한 정보를 추가하여 이름을 맹글링합니다. C에서 함수 이름을 오버로드할 수 없기 때문에 AC 컴파일러는 이름을 맹글링할 필요가 없습니다. 함수 extern "C"
연결이 있다고 명시하면 C++ 컴파일러는 인수/매개변수 유형 정보를 사용된 이름에 추가하지 않습니다. 결합.
알다시피, extern "C"
연결을 명시적으로 지정하거나 블록을 사용하여 일련의 선언/정의를 그룹화하여 특정 연결을 가질 수 있습니다.
extern "C" void foo(int); extern "C" { void g(char); int i; }
기술에 관심이 있다면 C++03 표준의 섹션 7.5에 나열되어 있습니다. 여기에 간단한 요약이 있습니다( extern "C"
강조).
extern "C"
는 연결 사양입니다.extern "C"
는 클래스 멤버에 대해 무시됩니다.extern "C"
는 함수가 외부 연결을 갖도록 강제합니다(정적으로 만들 수 없음)static
inside extern "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" }
내가 상상하는 것은 거의 동일한 것을 달성합니다.
어느 쪽이 더 나은지 확실하지 않지만 둘 다 보았습니다.
무슨 일이 일어나고 있는지 확인하기 위해 g++
생성 바이너리를 디컴파일하십시오.
메인.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"
g++
gcc
의해 생성된 unmangled 기호를 예상하도록 지시g++
gcc
가 사용할 unmangled 기호를 생성하도록 지시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 함수에는 맹글링되지 않은 기호가 하나만 있으므로 추가 작업이 필요하지 않습니다.
메인.cpp
#include <cassert> #include "ch" int main() { assert(f() == 1); }
채널
#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
참조
#include "ch" int f(void) { return 1; }
운영:
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"
가 없으면 링크가 다음과 같이 실패합니다.
main.cpp:6: undefined reference to `f()'
g++
gcc
가 생성하지 않은 f
를 찾을 것으로 예상하기 때문입니다.
C 예제에서 실행 가능한 최소 C++
C에서 C++를 호출하는 것은 조금 더 어렵습니다. 노출하려는 각 함수의 비 맹글링 버전을 수동으로 만들어야 합니다.
여기에서는 C++ 함수 오버로드를 C에 노출하는 방법을 보여줍니다.
메인.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
가 찾을 수 없는 맹글링된 기호를 생성했기 때문입니다.
C++에서 C 헤더를 포함할 때 extern "c"
는 어디에 있습니까?
cstdio
와 같은 C 헤더의 C++ 버전은 https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html이 언급하는 #pragma GCC system_header
에 의존할 수 있습니다. "RS/6000 AIX, GCC와 같은 일부 대상에서 C++로 컴파일할 때 모든 시스템 헤더를 'extern "C"' 블록으로 암묵적으로 둘러싸고 있습니다." 하지만 완전히 확인하지는 않았습니다./usr/include/unistd.h
와 같은 POSIX 헤더는 다음에서 다룹니다. 표준 POSIX C 헤더를 포함하려면 extern "C" 블록이 필요합니까? __BEGIN_DECLS
를 통해 Ubuntu 20.04에서 재생산됩니다. __BEGIN_DECLS
#include <features.h>
를 통해 포함됩니다.Ubuntu 18.04에서 테스트되었습니다.
모든 C++ 프로그램에서 모든 비정적 함수는 이진 파일에 기호로 표시됩니다. 이러한 기호는 프로그램에서 기능을 고유하게 식별하는 특수 텍스트 문자열입니다.
C에서 기호 이름은 함수 이름과 동일합니다. 이것은 C에서 두 개의 비정적 함수가 같은 이름을 가질 수 없기 때문에 가능합니다.
C++는 오버로딩을 허용하고 클래스, 멤버 함수, 예외 사양과 같이 C에는 없는 많은 기능을 가지고 있기 때문에 단순히 함수 이름을 기호 이름으로 사용할 수 없습니다. 이 문제를 해결하기 위해 C++는 함수 이름과 필요한 모든 정보(예: 인수의 수 및 크기)를 컴파일러와 링커에서만 처리되는 이상한 문자열로 변환하는 소위 이름 맹글링을 사용합니다.
따라서 함수를 extern C로 지정하면 컴파일러에서 이름 맹글링을 수행하지 않으며 해당 기호 이름을 함수 이름으로 사용하여 직접 액세스할 수 있습니다.
이것은 이러한 함수를 호출하기 위해 dlsym()
및 dlopen()
을 사용할 때 편리합니다.
대부분의 프로그래밍 언어는 기존 프로그래밍 언어 위에 구축되지 않습니다. 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
vs 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 함수 이름을 조작하지 마십시오"라고 말합니다. 그러나 다른 레거시 C 파일, "parent.h", "child.h" 등의 s 함수 이름 include
하는 "parent.c"라는 레거시 C 파일이 있다고 상상해 보십시오. 레거시 "parent.c" 파일이 C++ 컴파일러를 통해 실행하면 함수 이름이 수정되고 "parent.h", "child.h" 등에 지정된 함수 이름과 더 이상 일치하지 않습니다. 따라서 해당 외부 파일의 함수 이름도 필요합니다. 망할. 종속성이 많은 복잡한 C 프로그램에서 함수 이름을 변경하면 코드가 깨질 수 있습니다. 따라서 C++ 컴파일러에 함수 이름을 맹글링하지 않도록 지시할 수 있는 키워드를 제공하는 것이 편리할 수 있습니다.
extern "C"
키워드는 C++ 컴파일러에게 C 함수 이름을 맹글링(이름 변경)하지 않도록 지시합니다.
예를 들어:
extern "C" void printMe(int a);
어떤 C 헤더도 단순히 extern "C"로 래핑하여 C++와 호환되도록 만들 수 없습니다. C 헤더의 식별자가 C++ 키워드와 충돌하면 C++ 컴파일러는 이에 대해 불평합니다.
예를 들어, 다음 코드가 g++에서 실패하는 것을 보았습니다.
extern "C" { struct method { int virtual; }; }
다소 이해가 되지만 C 코드를 C++로 이식할 때 염두에 두어야 할 사항입니다.
이 함수는 함수 이름이되지 않음을 의미한다는 것을 C.에서 연습에서 호출 할 것을 같은 방식으로 함수의 링크 변경 망가을 .
링크 단계에서 C와 C++로 컴파일된 함수의 이름이 다르기 때문에 링크할 때 C 스타일에서 해당 함수의 이름을 조회하도록 C++ 컴파일러에 알립니다.
extern "C"
는 C++ 컴파일러에서 인식하고 언급된 함수가 C 스타일로 컴파일(또는 컴파일될) 예정임을 컴파일러에 알리기 위한 것이므로 링크하는 동안 C에서 함수의 올바른 버전으로 링크됩니다.
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) { // // }
나는 dll(동적 링크 라이브러리) 파일에 대해 '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); }
이 답변은 참을성 없는/마감 시간이 있는 사람을 위한 것입니다. 부분/간단한 설명만 아래에 있습니다.
그래서
C++에서 이름 맹글링으로 각 기능을 고유하게 식별
C에서는 이름 맹글링이 없어도 각 기능을 고유하게 식별합니다.
C++의 동작을 변경하려면, 즉 특정 함수에 대해 이름 맹글링이 발생하지 않도록 지정하려면 dll에서 특정 이름의 함수를 내보내는 것과 같이 어떤 이유로든 함수 이름 앞에 extern "C"를 사용할 수 있습니다. , 클라이언트가 사용할 수 있습니다.
더 자세한/더 정확한 답변을 보려면 다른 답변을 읽으십시오.
C 컴파일러에 의해 컴파일된 함수 void f()와 C++ 컴파일러에 의해 컴파일된 같은 이름의 함수 void f()는 같은 함수가 아닙니다. 해당 함수를 C로 작성한 다음 C++에서 호출하려고 하면 링커는 C++ 함수를 찾고 C 함수를 찾지 않습니다.
extern "C"는 C++ 컴파일러에 C 컴파일러에 의해 컴파일된 함수가 있음을 알려줍니다. C 컴파일러에 의해 컴파일되었다고 말하면 C++ 컴파일러는 이를 올바르게 호출하는 방법을 알게 됩니다.
또한 C++ 컴파일러는 C 컴파일러가 호출할 수 있는 방식으로 C++ 함수를 컴파일할 수 있습니다. 그 함수는 공식적으로는 C 함수이지만 C++ 컴파일러에 의해 컴파일되기 때문에 모든 C++ 기능을 사용할 수 있고 모든 C++ 키워드를 갖습니다.
C와 C++를 혼합할 때(즉, a. C++에서 C 함수 호출, b. C에서 C++ 함수 호출), C++ 이름 맹글링으로 인해 연결 문제가 발생합니다. 기술적으로 말하면 이 문제는 호출 수신자 함수가 해당 컴파일러를 사용하여 이미 바이너리(대부분 *.a 라이브러리 파일)로 컴파일된 경우에만 발생합니다.
따라서 C++에서 이름 맹글링을 비활성화하려면 extern "C"를 사용해야 합니다.
다른 좋은 답변과 충돌하지 않고 약간의 예를 추가하겠습니다.
정확히 C++ 컴파일러 가 하는 일: 컴파일 과정에서 이름을 엉망으로 만들기 때문에 컴파일러에게 C
구현을 특별히 취급하도록 지시해야 합니다.
C++ 클래스를 만들고 extern "C"
추가할 때 C++ 컴파일러에 C 호출 규칙을 사용하고 있음을 알리는 것입니다.
이유(C++에서 C 구현을 호출함): C++에서 C 함수를 호출하거나 C에서 C++ 함수를 호출하려고 합니다(C++ 클래스 ... 등은 C에서 작동하지 않음).
extern "C" 사용법에 대한 geeks 설명은 geeks for geeks인 아래 링크를 참조하십시오. 아래 페이지에서 중요한 정보 추가
f() 함수의 다음 선언을 고려하십시오.
int f (void) { return 1; } int f (int) { return 0; } void g (void) { int i = f(), j = f(0); }
C++ 컴파일러는 위의 이름을 다음으로 맹글링할 수 있습니다(출처: Wiki)
int __f_v (void) { return 1; } int __f_i (int) { return 0; } void __g_v (void) { int i = __f_v(), j = __f_i(0); }
출처 : http:www.stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c
Java 열거형 멤버 비교: == 또는 equals()? (0) | 2021.12.26 |
---|---|
jQuery를 사용하여 Ajax 요청 중단 (0) | 2021.12.26 |
PostgreSQL 명령줄 유틸리티를 종료하는 방법: psql (0) | 2021.12.26 |
값으로 배열 복사 (0) | 2021.12.26 |
원자 속성과 비 원자 속성의 차이점은 무엇입니까? (0) | 2021.12.26 |