C 함수는 왜 네임 매니지먼트가 안 되나요?
최근에 인터뷰를 했는데 한 가지 질문이 있는데, 이 질문의 용도는extern "C"
C++ 코드로 표시됩니다.C는 네임 매니징을 사용하지 않기 때문에 C++ 코드로 C 함수를 사용하는 것이라고 답변했습니다.C는 왜 이름 조작을 하지 않느냐고 물었고 솔직히 대답할 수 없었습니다.
C++ 컴파일러가 함수를 컴파일 할 때 주로 C++에 같은 이름의 함수를 오버로드 할 수 있기 때문에 함수에 특별한 이름을 붙이는 것으로 알고 있습니다.C에서 함수의 이름은 같거나 앞에 _가 붙어 있을 수 있습니다.
질문입니다.C++ 컴파일러가 C함수도 망가지게 하는 것이 무슨 문제입니까?컴파일러가 그들에게 어떤 이름을 붙여주든 상관없다고 생각했을 겁니다.C와 C++에서는 같은 방법으로 함수를 호출합니다.
위에서 어느 정도 답변한 내용이지만, 문맥에 맞게 설명하겠습니다.
먼저, C가 먼저였다.따라서 C가 하는 일은 일종의 디폴트입니다.그것은 단지 그렇게 하지 않기 때문에 이름을 뒤죽박죽으로.함수 이름은 함수 이름입니다.글로벌은 글로벌 등입니다.
그리고 C++가 나왔습니다.C++는 C와 동일한 링커를 사용할 수 있고 C로 작성된 코드로 링크할 수 있기를 원했습니다.그러나 C++는 C의 '망글링'(또는 그 결여)을 그대로 둘 수 없었다.다음의 예를 참조해 주세요.
int function(int a);
int function();
C++ 에서는, 이것들은 별개의 본체를 가지는 별개의 함수입니다.둘 다 망가지지 않으면 둘 다 "함수"(또는 "_함수")라고 불리며 링커는 기호의 재정의에 대해 불만을 제기합니다.C++ 솔루션은 인수 유형을 함수 이름으로 뭉치는 것이었습니다.그래서 하나는_function_int
다른 하나는_function_void
(실제 머글링 방식이 아님) 충돌은 회피됩니다.
이제 우리에게 문제가 남았다.한다면int function(int a)
C 모듈에서 정의되었으며, 우리는 단지 그 헤더(즉 선언)를 C++ 코드로 가져가고 그것을 사용하여 컴파일러는 링커에 Import 명령을 생성합니다._function_int
함수가 정의되었을 때 C 모듈에서는 그렇게 불리지 않았습니다.라고 불렸습니다._function
그러면 링커 오류가 발생합니다.
이 오류를 피하기 위해 함수를 선언하는 동안 C 컴파일러에 의해 링크되거나 컴파일되도록 설계된 함수임을 컴파일러에 알립니다.
extern "C" int function(int a);
C++ 컴파일러가 Import를 인식하게 되었습니다._function
보다는_function_int
, 그리고 모든 것이 좋습니다.
MSVC는 실제로는 간단한 방법으로 C 이름을 뭉개고 있습니다.때때로 추가된다.@4
다른 작은 숫자일 수도 있습니다.이것은, 콜의 표기법과 스택의 청소의 필요성에 관련하고 있습니다.
그래서 그 전제는 단지 결함이 있다.
C++ 컴파일러가 C 함수를 망치는 것이 무슨 문제입니까?
그것들은 더 이상 C 함수가 아닙니다.
함수는 시그니처와 정의뿐만이 아닙니다.함수의 동작방법은 주로 호출규칙 등의 요소에 의해 결정됩니다.플랫폼에서 사용하도록 지정된 "응용 프로그램 이진 인터페이스"는 시스템 간의 통신 방법을 설명합니다.시스템에서 사용 중인 C++ ABI는 이름 망글링 방식을 지정하여 해당 시스템상의 프로그램이 라이브러리 등의 함수를 호출하는 방법을 알 수 있도록 합니다(C++ Itanium ABI를 읽어보십시오). 왜 필요한지 금방 알 수 있을 것입니다.)
시스템상의 CABI에도 동일하게 적용됩니다.일부 CABI는 실제로 이름 망글링 스킴(예: Visual Studio)을 가지고 있습니다.따라서 이것은 "이름 망글링 끄기"가 아니라 특정 기능을 위해 C++ ABI에서 CABI로 전환하는 것입니다.C 함수는 C 함수로 마크하고 C ABI(C++ ABI가 아닌)가 관련되어 있습니다.선언은 정의와 일치해야 합니다(같은 프로젝트 또는 일부 서드파티 라이브러리의 경우). 그렇지 않으면 선언은 의미가 없습니다.그렇지 않으면 시스템이 이러한 기능을 검색/기동하는 방법을 인식할 수 없게 됩니다.
플랫폼이 C와 C++의 ABI를 동일하다고 정의하지 않고 이 "문제"를 해소하는 이유는 부분적으로 과거입니다.원래의 CABI는 네임스페이스, 클래스 및 연산자 오버로드가 있는 C++에는 충분하지 않았습니다.이 모든 것이 어떻게든 심볼 이름으로 컴퓨터 친화적으로 표현되어야 합니다.현재 C++ 프로그램을 C++에 준거시키는 것은 C 커뮤니티에서 불공평하며, C 커뮤니티는 상호 운용성을 원하는 다른 사람들을 위해서만 훨씬 더 복잡한 ABI를 견뎌야 한다.
일부 프로그램은 C로 작성되고 일부는 다른 언어로 작성됩니다(대부분 어셈블리 언어, 때로는 Pascal, FORTRAN 또는 기타).또한 프로그램에 포함된 컴포넌트가 모든 소스 코드를 가지고 있지 않을 수 있는 다른 사용자에 의해 작성된 컴포넌트가 다른 경우도 있습니다.
대부분의 플랫폼에는 특정 유형의 인수를 받아들여 특정 유형의 값을 반환하는 특정 이름의 함수를 생성하기 위해 컴파일러가 무엇을 해야 하는지를 기술하는 규격이 있습니다.경우에 따라서는, ABI는 복수의 「호출 규약」을 정의할 수 있습니다.이러한 시스템의 컴파일러는, 특정의 함수에 사용할 필요가 있는 호출 규약을 나타내는 수단을 제공하는 경우가 많습니다.예를 들어 Macintosh에서 대부분의 Toolbox 루틴은 Pascal 호출 규칙을 사용하므로 "LineTo"와 같은 프로토타입은 다음과 같습니다.
/* Note that there are no underscores before the "pascal" keyword because
the Toolbox was written in the early 1980s, before the Standard and its
underscore convention were published */
pascal void LineTo(short x, short y);
프로젝트 내의 모든 코드가 동일한 컴파일러를 사용하여 컴파일된 경우, 각 함수에 대해 컴파일러가 내보낸 이름이 무엇인지는 중요하지 않습니다.그러나 대부분의 경우 다른 툴을 사용하여 컴파일된 함수를 호출하여 현재 컴파일러로 재컴파일할 수 없는 C 코드가 필요합니다.따라서 이러한 기능을 사용하려면 링커 이름을 정의할 수 있어야 합니다.
지금까지의 접선적인 논의에 대해서, 또 하나의 답을 덧붙이겠습니다.
CABI(애플리케이션 바이너리 인터페이스)는 원래 역순서(오른쪽에서 왼쪽으로 누름)로 스택의 인수를 전달하도록 요구했으며, 여기서 호출자는 스택 스토리지를 개방합니다.현대의 ABI는 실제로 전달 인수를 위해 레지스터를 사용하지만, 많은 머글링 고려사항은 원래의 스택 인수 전달로 돌아간다.
반면, 원래의 Pascal ABI는 인수를 왼쪽에서 오른쪽으로 밀어냈고, 착신자는 인수를 터트려야 했다.원본 CABI는 두 가지 중요한 점에서 원본 Pascal ABI보다 우수합니다.인수 푸시 순서는 첫 번째 인수의 스택오프셋이 항상 알려진 것을 의미하며, 여기서 초기 인수는 다른 인수의 수를 제어합니다(ala).printf
).
CABI가 우위에 있는 두 번째 방법은 발신자와 착신자가 인수의 수에 동의하지 않는 경우의 동작입니다.C의 경우 마지막 인수가 지난 인수에 실제로 액세스하지 않는 한 나쁜 일은 발생하지 않습니다.Pascal에서는 잘못된 수의 인수가 스택에서 팝업되어 스택 전체가 파손됩니다.
최초의 Windows 3.1 ABI는 Pascal을 기반으로 합니다.따라서 Pascal ABI(왼쪽에서 오른쪽으로의 인수, 콜리 팝)를 사용했다.인수번호가 일치하지 않으면 스택이 파손될 수 있으므로 망글링 방식이 형성되었습니다.각 함수명은 인수의 크기(바이트 단위)를 나타내는 숫자와 함께 뭉쳐져 있습니다.따라서 16비트 머신에서는 다음 함수(C 구문)가 사용됩니다.
int function(int a)
부서졌다function@2
,왜냐면int
폭은 2바이트입니다.이는 선언과 정의가 일치하지 않을 경우 실행 시 스택이 파손되지 않고 링커가 함수를 찾을 수 없도록 하기 위해 수행되었습니다.반대로 프로그램이 링크되면 콜 종료 시 스택에서 올바른 바이트 수가 팝되었는지 확인할 수 있습니다.
32비트 Windows 이후에는 ABI를 사용합니다.Pascal ABI와 유사하지만 푸시 순서는 오른쪽에서 왼쪽으로 C와 같습니다.Pascal ABI와 같이 이름을 망글링하면 인수 바이트 크기를 함수 이름으로 망글링하여 스택 손상을 방지합니다.
다른 곳에서 제기된 주장과는 달리, CABI는 Visual Studio에서도 함수 이름을 조작하지 않습니다.반대로, 머글링 기능은,stdcall
ABI 사양은 VS만의 것이 아닙니다.GCC는 Linux용 컴파일 시에도 이 ABI를 지원합니다.이는 자체 로더를 사용하여 Linux 컴파일된 이진 파일을 Windows 컴파일된 DLL로 런타임 링크하는 Wine에 의해 광범위하게 사용됩니다.
그들이 "못한다"는 것이 아니라, 그들은 일반적으로 그렇지 않다.
내의 하려면 C 내의 함수를 호출해야 합니다.foo(int x, const char *y)
가 그것을 C++ 컴파일러로 것은foo_I_cCP()
(혹은 어떤 것이든 간에, 방금 즉석에서 난도질 계획을 세웠습니다) 할 수 있기 때문입니다.
이 이름은 해결되지 않으며 함수는 C에 있으며 인수 유형 목록에 따라 이름이 달라지지 않습니다.따라서 C++ 컴파일러는 이것을 알고 있어야 하며, 머글링을 피하기 위해 해당 함수를 C로 표시해야 합니다.
상기 C 함수는 사전에 컴파일된 바이너리와 헤더만 가지고 있는 소스 코드가 없는 라이브러리에 있을 수 있습니다.따라서 C++ 컴파일러는 "그것만의 것"을 수행할 수 없습니다.또한 라이브러리의 내용을 변경할 수도 없습니다.
C++ 컴파일러는 이름 망글링을 사용하여 오버로드된 함수의 고유 기호 이름을 사용할 수 있습니다.이러한 함수의 시그니처는 동일하지 않습니다.기본적으로 인수 유형도 인코딩하므로 함수 기반 수준에서 다형성이 가능합니다.
C는 함수를 오버로드할 수 없기 때문에 이 기능을 필요로 하지 않습니다.
이름 망글링은 'C++ ABI'에 의존할 수 없는 유일한 이유는 아닙니다.
C++는 C코드에 대해 링크하거나 링크하는 C코드와 상호 운용할 수 있기를 원합니다.
C 에서는, 이름이 일치하지 않는 함수명이 필요합니다.
C++가 그것을 망가뜨린 경우, C에서 내보낸 비혼합 함수를 찾을 수 없거나, C에서 내보낸 함수를 찾을 수 없습니다.C 링커는, C++ 로부터의 착신인지 아닌지를 모르기 때문에, C 링커 자신이 기대하는 이름을 취득할 필요가 있습니다.
C 함수 및 변수의 이름을 망글링하면 링크 시 해당 유형을 확인할 수 있습니다.현재 모든 (?)C 실장에서는 변수를 1개의 파일로 정의하고 다른 파일의 함수로 호출할 수 있습니다. 잘못된 시그니처를 할 수 예: " " " " " " " " " " " " ( " 。void fopen(double)
이치노
나는 1991년 망글링의 사용을 통해 C 변수와 함수의 타입 세이프 연계 방식을 제안했다.이 계획은 채택되지 않았습니다.다른 사람들이 여기서 지적했듯이 하위 호환성을 파괴할 수 있기 때문입니다.
언급URL : https://stackoverflow.com/questions/36621845/why-cant-c-functions-be-name-mangled
'programing' 카테고리의 다른 글
Python: * 및 **가 / 및 sqrt()보다 빠른 이유는 무엇입니까? (0) | 2022.07.13 |
---|---|
JAX-RS 및 Jersey를 사용한 REST 토큰 기반 인증 구현 방법 (0) | 2022.07.13 |
Vue Router가 루트로 이동하지만 잘못된 컴포넌트를 로드함 (0) | 2022.07.13 |
노드용 파일을 포함합니다.JS(vue) (0) | 2022.07.13 |
가치 없는 Vue 컴포넌트 소품 (0) | 2022.07.13 |