extern "C"
C ++ 코드에 정확히 들어가는 것은 무엇입니까 ?
예를 들면 다음과 같습니다.
extern "C" {
void foo();
}
foo()
기능 이있는 Cpp 파일이 있음을 의미 합니다.
extern "C"
C ++ 코드에 정확히 들어가는 것은 무엇입니까 ?
예를 들면 다음과 같습니다.
extern "C" {
void foo();
}
foo()
기능 이있는 Cpp 파일이 있음을 의미 합니다.
답변:
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" { int i; }
정의입니다. 의 비정의 옆에있는 의도 한 것이 아닐 수도 있습니다 void g(char);
. 그것을 비정의로 만들려면 필요합니다 extern "C" { extern int i; }
. 반면에, 중괄호가없는 한 선언 구문은 선언을 비 정의을 수행합니다 extern "C" int i;
과 동일extern "C" { extern int i; }
정보가 아직 게시되지 않았기 때문에 약간의 정보를 추가하고 싶었습니다.
다음과 같이 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"
}
나는 똑같은 일을 성취한다고 상상합니다.
어느 쪽이 더 좋은지 잘 모르겠지만 둘 다 보았습니다.
extern "C"
헤더에서 보았으므로 엉킴없는 이름을 찾습니다 . 그것은이 기술을 여러 번 사용하여 훌륭하게 작동합니다.
extern "C"
는 헤더를 포함하기 전이나 후에 만날 지 신경 쓰지 못했습니다 . 컴파일러에 도달 할 때까지는 전처리 된 텍스트 스트림 중 하나 일뿐입니다.
g++
지난 17 년 중 언제라도 어느 버전 에서든 어떤 버전의 버전 에서도이 문제가 발생하지 않았습니다. 첫 번째 예제의 요점은 C 또는 C ++ 컴파일러를 사용하는지 여부는 중요하지 않으며 extern "C"
블록 의 이름에 대해서는 이름 변환이 수행되지 않는다는 것 입니다.
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"
전화를 걸 때 둘 다 필요 합니다.
g++
에 의해 생산 unmangled 문자 기대gcc
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
생산하지 않았다.
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
입니다.
우분투에서 테스트 18.04.
extern "C" {
당신이 전화를하는 데 도움이 C ++ 프로그램 내에서 unmangled C의 기능을 뿐만 아니라, C 프로그램 내에서 기능 ++ unmangled C 다른 답변은 그리 명확하지 않습니다, 그리고 당신의 별개의 예를 보여 있기 때문에) 2 마다. 감사!
모든 C ++ 프로그램에서 모든 비 정적 함수는 2 진 파일에서 기호로 표시됩니다. 이 기호는 프로그램에서 기능을 고유하게 식별하는 특수 텍스트 문자열입니다.
C에서 기호 이름은 함수 이름과 동일합니다. C에서는 두 개의 비 정적 함수가 동일한 이름을 가질 수 없기 때문에 가능합니다.
C ++은 오버로딩을 허용하고 클래스, 멤버 함수, 예외 사양과 같이 C가 지원하지 않는 많은 기능을 가지고 있기 때문에 단순히 함수 이름을 기호 이름으로 사용할 수 없습니다. 이를 해결하기 위해 C ++은 함수 이름과 필요한 모든 정보 (인수의 수 및 크기 등)를 컴파일러와 링커에서만 처리하는 이상한 문자열로 변환하는 이른바 이름 관리 (name mangling)를 사용합니다.
따라서 함수를 extern C로 지정하면 컴파일러는 이름 변환을 수행하지 않으며 기호 이름을 함수 이름으로 사용하여 직접 액세스 할 수 있습니다.
이러한 기능 을 사용 dlsym()
하고 dlopen()
호출 할 때 편리 합니다.
대부분의 프로그래밍 언어는 기존 프로그래밍 언어를 기반으로하지 않습니다. 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
없습니까? 헤더 파일이없고 소스 파일 (구현 만)이 있고 함수 포인터를 통해 그 기능을 사용한다면 의미합니다. 이 상태에서는 이름에 관계없이 함수를 사용했습니다.
extern "C"로 감싸서 C 헤더를 C ++과 호환되도록 만들 수는 없습니다. C- 헤더의 식별자가 C ++ 키워드와 충돌하면 C ++ 컴파일러는 이에 대해 불평합니다.
예를 들어, g ++에서 다음 코드가 실패하는 것을 보았습니다.
extern "C" {
struct method {
int virtual;
};
}
Kinda는 의미가 있지만 C 코드를 C ++로 이식 할 때 명심해야합니다.
extern "C"
다른 답변에서 설명한대로 C 연결을 사용하는 것을 의미합니다. "내용을 C로 컴파일"또는 다른 것을 의미하는 것은 아닙니다. int virtual;
C ++에서는 유효하지 않으며 다른 연결을 지정해도 변경되지 않습니다.
C에서 함수를 호출 할 수있는 방식으로 함수의 링크를 변경합니다. 실제로 함수 이름이 엉망 이되지 않습니다 .
undname
합니다.
이전에 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);
}
extern "C"
와 __declspec(dllexport)
관련이 없습니다. 전자는 심볼 장식을 제어하고 후자는 내보내기 항목을 생성합니다. C ++ 이름 데코레이션을 사용하여 심볼을 내보낼 수도 있습니다. 이 질문의 요점을 완전히 잃어버린 것 외에도 코드 샘플에는 다른 실수도 있습니다. 하나 main
는 DLL에서 내 보낸 값을 반환하지 않습니다. 또는 그 문제에 대한 전화 회의. 가져올 때 임의 호출 규칙 ( WINAPI
)의 속성을 지정하고 32 비트 빌드 ( _main
또는 이어야 함 _main@0
)에 잘못된 기호를 사용합니다 . 죄송합니다, -1
void*
하지만 구현은 아무것도 리턴하지 않습니다. 정말 잘 날 것입니다 ...
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)
{
//
//
}
이 답변은 참을성이없는 / 마감일을 맞추기위한 것이며 일부 / 간단한 설명 만 아래에 있습니다.
따라서
C ++에서는 이름을 고유하게 식별하여 각 함수
를 고유하게 식별합니다.
C ++의 동작을 변경하려면, 즉 특정 함수에 대해 이름 변환 이 발생 하지 않도록 지정 하려면 dll에서 특정 이름을 가진 함수를 내보내는 등 어떤 이유로 든 함수 이름 앞에 extern "C" 를 사용할 수 있습니다. 클라이언트가 사용합니다.
더 자세하고 정확한 답변을 얻으려면 다른 답변을 읽으십시오.
다른 좋은 대답과 충돌하지 않고 약간의 예를 추가하겠습니다.
정확히 C ++ 컴파일러의 기능 : 컴파일 프로세스에서 이름을 엉망으로 만들므로 컴파일러에게 구현을 특별히 처리 하도록 지시해야합니다 C
.
C ++ 클래스를 만들고를 추가 할 때 extern "C"
C ++ 컴파일러에 C 호출 규칙을 사용하고 있다고 알려줍니다.
이유 (우리는 C ++에서 C 구현을 호출합니다) : C ++에서 C 함수를 호출하거나 C에서 C ++ 함수를 호출하려고합니다 (C ++ 클래스 ... 등은 C에서 작동하지 않음).
C 컴파일러에 의해 컴파일 된 void f () 함수와 C ++ 컴파일러에 의해 컴파일 된 void f () 같은 이름의 함수는 동일한 함수가 아닙니다. C로 해당 함수를 작성하고 C ++에서 호출하려고하면 링커가 C ++ 함수를 찾고 C 함수를 찾지 않습니다.
extern "C"는 C ++ 컴파일러에게 C 컴파일러에 의해 컴파일 된 함수가 있음을 알려줍니다. C 컴파일러에 의해 컴파일되었다고 말하면 C ++ 컴파일러는이를 올바르게 호출하는 방법을 알게됩니다.
또한 C ++ 컴파일러가 C 컴파일러가 호출 할 수있는 방식으로 C ++ 함수를 컴파일 할 수 있습니다. 이 함수는 공식적으로 C 함수이지만 C ++ 컴파일러에 의해 컴파일되므로 모든 C ++ 기능을 사용할 수 있으며 모든 C ++ 키워드가 있습니다.
extern "C"
함수를 컴파일 할 수 있으며 C 컴파일러가 컴파일 한 코드로 호출 할 수 있습니다 (일부 제약 조건에 따라 다름).