Windows에서 __cdecl 또는 __stdcall?
현재 DLL로 배포 될 Windows 용 C ++ 라이브러리를 개발 중입니다. 내 목표는 바이너리 상호 운용성을 극대화하는 것입니다. 보다 정확하게는 DLL을 다시 컴파일하지 않고도 여러 버전의 MSVC ++ 및 MinGW로 컴파일 된 코드에서 DLL의 함수를 사용할 수 있어야합니다. 그러나 어떤 호출 규칙이 가장 좋은지 cdecl
또는 stdcall
.
때때로 "C 호출 규칙은 컴파일러를 통틀어 동일하게 보장되는 유일한 것입니다."와 같은 말을 듣습니다. 이는 " 의 해석 cdecl
, 특히 값을 반환하는 방법에 있어 약간의 변형이 있습니다. "와 대조됩니다 . 이것은 특정 라이브러리 개발자 (예 : libsndfile )가 배포하는 DLL에서 눈에 보이는 문제없이 C 호출 규칙을 사용하는 것을 막지는 않는 것 같습니다 .
반면에 stdcall
호출 규칙은 잘 정의 된 것 같습니다. 내가 말한 바에 따르면 모든 Windows 컴파일러는 기본적으로 Win32 및 COM에 사용되는 규칙이기 때문에이를 따라야합니다. 이것은 Win32 / COM을 지원하지 않는 Windows 컴파일러가 그다지 유용하지 않다는 가정을 기반으로합니다. 포럼에 게시 된 많은 코드 조각은 기능을 선언 stdcall
하지만 이유 를 명확하게 설명하는 단일 게시물을 찾을 수없는 것 같습니다 .
상충되는 정보가 너무 많고 검색 할 때마다 서로 다른 답변을 제공하므로 둘 사이를 결정하는 데 도움이되지 않습니다. 나는 왜 내가 다른 것보다 하나를 선택해야하는지 (또는 두 개가 동등한 이유)에 대해 명확하고 자세하며 논쟁적인 설명을 찾고 있습니다.
이 질문은 "클래식"함수뿐만 아니라 가상 멤버 함수 호출에도 적용됩니다. 대부분의 클라이언트 코드는 "인터페이스", 순수 가상 클래스 (예를 들어 여기 와 거기에 설명 된 패턴을 따름)를 통해 내 DLL과 인터페이스하기 때문 입니다.
방금 실제 테스트를 수행했습니다 (MSVC ++ 및 MinGW로 DLL 및 응용 프로그램을 컴파일 한 다음 혼합). 나타나는 것처럼 cdecl
호출 규칙으로 더 나은 결과를 얻었습니다 .
더 구체적으로, 문제 stdcall
는 MSVC ++가 .NET Framework를 사용하는 경우에도 DLL 내보내기 테이블의 이름을 엉망으로 만든다는 것 extern "C"
입니다. 예를 들어 foo
이된다 _foo@4
. 이것은 __declspec(dllexport)
DEF 파일을 사용할 때가 아니라를 사용할 때만 발생 합니다. 그러나 DEF 파일은 유지 관리가 번거롭고 사용하고 싶지 않습니다.
MSVC ++ 이름 맹 글링에는 두 가지 문제가 있습니다.
GetProcAddress
DLL에서 사용하면 약간 더 복잡해집니다.- 기본적으로 MinGW는 데코 레이팅 된 이름 앞에 undescore를 추가하지 않으므로 (예 : MinGW는
foo@4
대신을 사용 합니다_foo@4
) 연결을 복잡하게 만듭니다. 또한 "밑줄 버전"과 호환되지 않는 DLL 및 응용 프로그램의 "밑줄이 아닌 버전"이 갑자기 나타날 위험이 있습니다.
나는 cdecl
관례를 시도했다 : MSVC ++와 MinGW 간의 상호 운용성은 완벽하게 작동하고, 즉시 사용 가능하며, 이름은 DLL 내보내기 테이블에 장식되지 않은 상태로 유지됩니다. 가상 방법에서도 작동합니다.
이러한 이유로은 cdecl
저에게 확실한 승자입니다.
두 호출 규칙의 가장 큰 차이점은 " _ _cdecl"이 호출자에 대한 함수 호출 후 스택 균형을 조정하는 부담을 주므로 가변적 인 양의 인수를 가진 함수를 허용한다는 것입니다. "__stdcall"규칙은 본질적으로 "단순"하지만 이와 관련하여 유연성이 떨어집니다.
또한 관리 언어는 기본적으로 stdcall 규칙을 사용하므로 P / Invoke를 사용하는 사람은 cdecl을 사용하는 경우 호출 규칙을 명시 적으로 지정해야합니다.
따라서 모든 함수 서명이 정적으로 정의되면 cdecl이 아니라면 stdcall에 의지 할 것입니다.
보안 측면에서 __cdecl
규칙은 스택 할당을 해제해야하는 호출자이기 때문에 "안전"합니다. __stdcall
라이브러리 에서 일어날 수있는 일은 개발자가 스택을 적절하게 할당 해제하는 것을 잊었거나 공격자가 DLL의 스택을 손상시켜 (예 : API 후킹에 의해) 일부 코드를 삽입 할 수 있으며 호출자가 확인하지 않을 수 있습니다. 내 직감이 옳다는 것을 보여주는 CVS 보안 예제가 없습니다.
참고 URL : https://stackoverflow.com/questions/6511096/cdecl-or-stdcall-on-windows
'Development Tip' 카테고리의 다른 글
파이썬 소스 코드를 읽고 싶습니다. (0) | 2020.10.24 |
---|---|
동일한 ASP.NET MVC 작업에 대한 여러 동시 AJAX 호출로 인해 브라우저가 차단되는 이유는 무엇입니까? (0) | 2020.10.24 |
모든 표준 Android 아이콘 리소스는 어디에 있습니까? (0) | 2020.10.24 |
정적 변수는 언제 초기화됩니까? (0) | 2020.10.24 |
IQueryable을 반환하려면 (0) | 2020.10.24 |