C Run-Time 사용

이 문서에서는 C 런타임을 사용하는 방법을 설명합니다.

원래 제품 버전: Visual C++
원본 KB 번호: 94248

섹션 1: CRT(세 가지 형태의 C Run-Time) 라이브러리를 사용할 수 있습니다.

Win32 SDK와 함께 제공되는 세 가지 형태의 C 런타임 라이브러리가 있습니다.

  • LIBC. LIB는 단일 스레드 프로그램에 대한 정적으로 연결된 라이브러리입니다.

  • LIBCMT. LIB는 다중 스레드 프로그램을 지원하는 정적으로 연결된 라이브러리입니다.

  • CRTDLL. LIB는 다중 스레드 프로그램을 지원하는 CRTDLL.DLL 대한 가져오기 라이브러리입니다. CRTDLL.DLL 자체는 Windows NT 일부입니다.

Microsoft Visual C++ 32비트 버전에는 이러한 세 가지 양식도 포함되어 있지만 DLL의 CRT 이름은 MSVCRT입니다. Lib. DLL은 재배포할 수 있습니다. 해당 이름은 VC++ 버전(즉, MSVCRT10.DLL 또는 MSVCRT20.DLL)에 따라 달라집니다. 그러나 이 MSVCRT10.DLL Win32s에서는 지원되지 않지만 CRTDLL은 지원되지 않습니다. LIB는 Win32s에서 지원됩니다. MSVCRT20.DLL 두 가지 버전으로 제공됩니다. 하나는 Windows NT용이고 다른 하나는 Win32s용입니다.

섹션 2: DLL을 빌드할 때 CRT 라이브러리 사용

C 런타임 라이브러리를 사용하는 DLL을 빌드할 때 CRT가 제대로 초기화되었는지 확인합니다.

  1. 초기화 함수의 이름을 지정 DllMain() 해야 하며 진입점은 링커 옵션으로 지정해야 합니다. -entry:_DllMainCRTStartup@12

    또는

  2. DLL의 진입점은 프로세스 연결 및 프로세스 분리 시 명시적으로 호출 CRT_INIT() 해야 합니다.

이를 통해 C 런타임 라이브러리는 프로세스 또는 스레드가 DLL에 연결될 때 C 런타임 데이터를 올바르게 할당하고 초기화하고, 프로세스가 DLL에서 분리될 때 C 런타임 데이터를 제대로 클린, DLL의 전역 C++ 개체가 제대로 생성 및 소멸되도록 할 수 있습니다.

Win32 SDK 샘플은 모두 첫 번째 메서드를 사용합니다. 예제로 사용합니다. 또한 Win32 프로그래머의 참조 및 에 대한 DllEntryPoint() Visual C++ 설명서를 참조하세요 DllMain(). DllMainCRTStartup() 가 있는 경우 및 CRT_INIT() 를 호출 CRT_INIT() 하여 애플리케이션의 DllMain()을 호출합니다.

두 번째 메서드를 사용하고 CRT 초기화 코드를 직접 호출하려는 경우 및 DllMain()를 사용하는 DllMainCRTStartup() 대신 다음 두 가지 기술이 있습니다.

  1. 초기화 코드를 수행하는 항목 함수가 없는 경우 를 DLL의 진입점으로 지정 CRT_INIT() 합니다. NTWIN32 포함한다고 가정합니다. @12로 정의 DLLENTRY 되는 MAK는 DLL의 링크 줄에 옵션을 추가합니다-entry:_CRT_INIT$(DLLENTRY).

    또는

  2. 고유한 DLL 진입점이 있는 경우 진입점에서 다음을 수행합니다.

    1. 에 이 프로토타입을 사용합니다.CRT_INIT()BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);

      반환 값에 대한 CRT_INIT() 자세한 내용은 DllEntryPoint 설명서를 참조하세요. 동일한 값이 반환됩니다.

    2. DLL_THREAD_ATTACH (이러한 플래그에 DLL_PROCESS_ATTACH 대한 자세한 내용은 Win32 API 참조의 DllEntryPoint 참조)에서 먼저 를 호출합니다. 먼저 C 런타임 함수가 호출되거나 부동 소수점 작업이 수행되기 전에 를 호출CRT_INIT()합니다.

    3. 사용자 고유의 프로세스/스레드 초기화/종료 코드를 호출합니다.

    4. DLL_THREAD_DETACH에서 DLL_PROCESS_DETACH 모든 C 런타임 함수가 호출되고 모든 부동 소수점 작업이 완료된 후 마지막으로 를 호출 CRT_INIT() 합니다.

진입점 CRT_INIT() 의 모든 매개 변수에 CRT_INIT() 전달해야 합니다. 이러한 매개 변수를 예상하므로 생략하면 안정적으로 작동하지 않을 수 있습니다(특히 프로세스 초기화 또는 종료가 필요한지 여부를 결정하는 데 fdwReason이 필요함).

다음은 DLL 진입점에서 이러한 호출 CRT_INIT() 을 수행할 시기와 방법을 보여 주는 기본 샘플 진입점 함수입니다.

BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH || fdwReason == DLL_THREAD_ATTACH)
    if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))
    return(FALSE);

    if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH)
    if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))
    return(FALSE);
    return(TRUE);
}

참고

-entry:_DllMainCRTStartup@12를 사용하는 DllMain() 경우에는 이 작업이 필요하지 않습니다.

섹션 3: NTWIN32 사용. MAK를 사용하여 빌드 프로세스 간소화

NTWIN32 정의된 매크로가 있습니다. 메이크파일을 단순화하고 충돌을 방지하기 위해 제대로 빌드되도록 하는 데 사용할 수 있는 MAK입니다. 이러한 이유로 Microsoft는 NTWIN32 사용하는 것이 좋습니다. MAK 및 그 안에 있는 매크로.

컴파일의 경우 을 사용합니다 $(cvarsdll) for apps/DLLs using CRT in a DLL.

연결하려면 다음 중 하나를 사용합니다.

  • $(conlibsdll) for console apps/DLLs using CRT in a DLL
  • $(guilibsdll) for GUI apps using CRT in a DLL

섹션 4: 여러 CRT 라이브러리를 사용할 때 발생하는 문제

C 런타임 호출을 만드는 애플리케이션이 C 런타임 호출을 만드는 DLL에 연결되는 경우 둘 다 정적으로 연결된 C 런타임 라이브러리(LIBC) 중 하나와 연결된 경우 주의해야 합니다. LIB 또는 LIBCMT. LIB), .EXE 및 DLL에는 모든 C 런타임 함수 및 전역 변수의 별도 복사본이 있습니다. 즉, C 런타임 데이터는 .EXE DLL 간에 공유할 수 없습니다. 그 결과 발생할 수 있는 몇 가지 문제는 다음과 같습니다.

  • .EXE/DLL에서 다른 모듈로 버퍼링된 스트림 핸들 전달

  • .EXE/DLL에서 C 런타임 호출을 사용하여 메모리 할당 및 다른 모듈에서 다시 할당 또는 해제

  • .EXE/DLL에서 전역 errno 변수의 값을 확인하거나 설정하며 다른 모듈에서 동일할 것으로 예상합니다. 관련 문제는 errno를 사용하기 때문에 perror() C 런타임 오류가 발생한 반대 모듈에서 를 호출 perror() 하는 것입니다.

이러한 문제를 방지하려면 .EXE 및 DLL을 CRTDLL과 연결합니다. LIB 또는 MSVCRT. LIB는 .EXE DLL에서 DLL의 CRT 내에 포함된 공통 함수 및 데이터 집합을 사용할 수 있도록 하고 스트림 핸들과 같은 C 런타임 데이터를 .EXE DLL에서 공유할 수 있습니다.

섹션 5: 라이브러리 형식 혼합

DLL을 CRTDLL과 연결할 수 있습니다. LIB/MSVCRT. CRT 데이터 구조를 혼합하고 CRT 파일 핸들 또는 CRT FILE* 포인터를 다른 모듈에 전달하지 않는 경우 .EXE 연결된 항목에 관계없이 LIB입니다.

라이브러리 형식을 혼합하는 경우 다음을 준수합니다.

  • CRT 파일 핸들은 해당 핸들을 만든 CRT 모듈에서만 작동할 수 있습니다.

  • CRT FILE* 포인터는 해당 포인터를 만든 CRT 모듈에서만 작동할 수 있습니다.

  • CRT 함수 malloc() 를 사용하여 할당된 메모리는 할당된 CRT 모듈에서만 해제되거나 다시 할당될 수 있습니다.

이를 설명하기 위해 다음 예제를 고려하세요.

  • .EXE MSVCRT와 연결됩니다. Lib
  • DLL A는 LIBCMT와 연결됩니다. Lib
  • DLL B는 CRTDLL과 연결됩니다. Lib

.EXE 또는 를 사용하여 _create() CRT 파일 핸들을 만드는 경우 이 파일 핸들은 .EXE 파일의 , _read(), _write(), _close()등으로만 전달_lseek()될 수 _open()있습니다. 이 CRT 파일 핸들을 DLL에 전달하지 마세요. DLL에서 가져온 CRT 파일 핸들을 다른 DLL 또는 .EXE 전달하지 마세요.

DLL A가 를 사용하여 메모리 malloc()블록을 할당하는 경우 DLL A만 를 _expand()호출free()하거나 realloc() 해당 블록에서 작동할 수 있습니다. DLL A에서 를 호출 malloc() 하고 .EXE 또는 DLL B에서 해당 블록을 해제하려고 할 수 없습니다.

참고

세 모듈이 모두 CRTDLL과 연결된 경우 LIB 또는 세 가지 모두 MSVCRT와 연결되었습니다. IB, 이러한 제한은 적용되지 않습니다.

LIBC와 DLL을 연결하는 경우 LIB는 다중 스레드 프로그램에서 이러한 DLL을 호출할 가능성이 있는 경우 DLL이 DLL에서 실행되는 여러 스레드를 동시에 지원하지 않으므로 주요 문제가 발생할 수 있습니다. 다중 스레드 프로그램에서 DLL을 호출할 가능성이 있는 경우 다중 스레드 프로그램(LIBCMT)을 지원하는 라이브러리 중 하나와 연결해야 합니다. LIB, CRTDLL. LIB 또는 MSVCRT. LIB).