Freigeben über


Verwenden der C-Laufzeit

In diesem Artikel wird beschrieben, wie Sie die C-Laufzeit verwenden.

Originalproduktversion: Visual C++
Ursprüngliche KB-Nummer: 94248

Abschnitt 1: Drei Formen von C-Laufzeitbibliotheken (CRT) sind verfügbar.

Es gibt drei Formen der C-Laufzeitbibliothek, die mit dem Win32 SDK bereitgestellt wird:

  • LIBC. LIB ist eine statisch verknüpfte Bibliothek für Singlethread-Programme.

  • LIBCMT. LIB ist eine statisch verknüpfte Bibliothek, die Multithread-Programme unterstützt.

  • CRTDLL. LIB ist eine Importbibliothek für CRTDLL.DLL, die auch Multithreadprogramme unterstützt. CRTDLL.DLL selbst ist Teil von Windows NT.

Microsoft Visual C++ 32-Bit-Edition enthält diese drei Formen, aber der CRT in einer DLL heißt MSVCRT. BEFREIEN. Die DLL ist verteilbar. Der Name hängt von der Version von VC++ ab (d. a. MSVCRT10.DLL oder MSVCRT20.DLL). Beachten Sie jedoch, dass MSVCRT10.DLL für Win32s nicht unterstützt wird, während CRTDLL. LIB wird für Win32s unterstützt. MSVCRT20.DLL kommt in zwei Versionen: eines für Windows NT und das andere für Win32s.

Abschnitt 2: Verwenden der CRT-Bibliotheken beim Erstellen einer DLL

Beim Erstellen einer DLL, die eine der C-Laufzeitbibliotheken verwendet, um sicherzustellen, dass das CRT ordnungsgemäß initialisiert ist, entweder

  1. Die Initialisierungsfunktion muss benannt DllMain() werden, und der Einstiegspunkt muss mit der Linkeroption angegeben werden. -entry:_DllMainCRTStartup@12

    oder

  2. Der Einstiegspunkt der DLL muss explizit auf Prozessanfügung und Prozessablösung aufrufen CRT_INIT() .

Dadurch können die C-Laufzeitbibliotheken C-Laufzeitdaten ordnungsgemäß zuordnen und initialisieren, wenn ein Prozess oder Thread an die DLL angefügt wird, um C-Laufzeitdaten ordnungsgemäß zu bereinigen, wenn ein Prozess von der DLL getrennt wird, und für globale C++-Objekte in der DLL ordnungsgemäß konstruiert und destruktiert zu werden.

Die Win32 SDK-Beispiele verwenden alle die erste Methode. Verwenden Sie sie als Beispiel. Weitere Informationen finden Sie in der Win32-Programmierreferenz für DllEntryPoint() und in der Visual C++-Dokumentation für DllMain(). Beachten Sie, dass DllMainCRTStartup() Aufrufe und CRT_INIT() aufruft CRT_INIT() die DllMain() Ihrer Anwendung, falls vorhanden.

Wenn Sie die zweite Methode verwenden und den CRT-Initialisierungscode selbst aufrufen möchten, statt ihn zu verwenden DllMainCRTStartup() , gibt DllMain()es zwei Techniken:

  1. Wenn keine Eintragsfunktion vorhanden ist, die Initialisierungscode ausführt, geben Sie CRT_INIT() als Einstiegspunkt der DLL an. Angenommen, Sie haben NTWIN32 eingeschlossen. MAK, der als @12 definiert DLLENTRY wird, fügen Sie der Linkzeile-entry:_CRT_INIT$(DLLENTRY) der DLL die Option hinzu.

    oder

  2. Wenn Sie über einen eigenen DLL-Einstiegspunkt verfügen, gehen Sie im Einstiegspunkt wie folgt vor:

    1. Verwenden Sie diesen Prototyp für CRT_INIT(): BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);

      Informationen zu CRT_INIT() Rückgabewerten finden Sie in der Dokumentation DllEntryPoint. Dieselben Werte werden zurückgegeben.

    2. On DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH (see DllEntryPoint in the Win32 API reference for more information on these flags), call CRT_INIT(), first, before any C Run-time functions are called or any floating-point operations are perform.

    3. Rufen Sie ihren eigenen Prozess-/Threadinitialisierungs-/Beendigungscode auf.

    4. Am DLL_PROCESS_DETACH und DLL_THREAD_DETACH, letzten Aufruf CRT_INIT() , nachdem alle C-Laufzeitfunktionen aufgerufen wurden und alle Gleitkommavorgänge abgeschlossen sind.

Achten Sie darauf, alle Parameter des Einstiegspunkts weiterzuleiten CRT_INIT() ; CRT_INIT() erwartet diese Parameter, sodass die Dinge möglicherweise nicht zuverlässig funktionieren, wenn sie weggelassen werden (insbesondere ist fdwReason erforderlich, um zu bestimmen, ob die Prozessinitialisierung oder Beendigung erforderlich ist).

Nachfolgend finden Sie eine Beispieleinstiegspunktfunktion, die zeigt, wann und wie diese Aufrufe CRT_INIT() im DLL-Einstiegspunkt ausgeführt werden:

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);
}

Notiz

Dies ist nicht erforderlich, wenn Sie verwenden DllMain() und -entry:_DllMainCRTStartup@12.

Abschnitt 3: Verwenden von NTWIN32. MAK zur Vereinfachung des Buildprozesses

In NTWIN32 sind Makros definiert. MAK, der verwendet werden kann, um Ihre Makefiles zu vereinfachen und sicherzustellen, dass sie ordnungsgemäß erstellt sind, um Konflikte zu vermeiden. Aus diesem Grund empfiehlt Microsoft dringend, NTWIN32 zu verwenden. MAK und die darin enthaltenen Makros.

Verwenden Sie für die Kompilierung Folgendes: $(cvarsdll) for apps/DLLs using CRT in a DLL.

Verwenden Sie zum Verknüpfen eine der folgenden Optionen:

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

Abschnitt 4: Probleme bei der Verwendung mehrerer CRT-Bibliotheken

Wenn eine Anwendung, die C-Laufzeitaufrufe ausführt, Links zu einer DLL herstellt, die auch C-Laufzeitaufrufe ausführt, beachten Sie, dass beide mit einer der statisch verknüpften C-Laufzeitbibliotheken (LIBC) verknüpft sind. LIB oder LIBCMT. LIB), die .EXE und DLL verfügen über separate Kopien aller C-Laufzeitfunktionen und globalen Variablen. Dies bedeutet, dass C-Laufzeitdaten nicht zwischen dem .EXE und der DLL gemeinsam genutzt werden können. Einige der Probleme, die als Ergebnis auftreten können, sind:

  • Übergeben von gepufferten Datenstromhandles von der .EXE/DLL an das andere Modul

  • Zuordnen des Arbeitsspeichers mit einem C-Laufzeitaufruf in der .EXE/DLL und Neuzuordnung oder Freigeben des Speichers im anderen Modul

  • Überprüfen oder Festlegen des Werts der globalen Errno-Variable in der .EXE/DLL und erwarten, dass sie im anderen Modul identisch ist. Ein verwandtes Problem wird im entgegengesetzten Modul aufgerufen perror() , von dem der C-Laufzeitfehler aufgetreten ist, da perror() errno verwendet.

Um diese Probleme zu vermeiden, verknüpfen Sie sowohl die .EXE als auch die DLL mit CRTDLL. LIB oder MSVCRT. LIB, mit der sowohl die .EXE als auch die DLL den allgemeinen Satz von Funktionen und Daten verwenden können, die in CRT in einer DLL enthalten sind, und C-Laufzeitdaten wie Datenstromhandles können dann sowohl vom .EXE als auch von der DLL gemeinsam genutzt werden.

Abschnitt 5: Mischen von Bibliothekstypen

Sie können Ihre DLL mit CRTDLL verknüpfen. LIB/MSVCRT. LIB unabhängig davon, mit was Ihre .EXE verknüpft ist, wenn Sie das Mischen von CRT-Datenstrukturen und das Übergeben von CRT-Dateihandles oder CRT FILE*-Zeigern an andere Module vermeiden.

Beim Mischen von Bibliothekstypen beachten Sie Folgendes:

  • CRT-Dateihandles dürfen nur vom CRT-Modul betrieben werden, das sie erstellt hat.

  • CRT FILE*-Zeiger dürfen nur vom CRT-Modul betrieben werden, das sie erstellt hat.

  • Der mit der CRT-Funktion malloc() zugewiesene Speicher kann nur vom CRT-Modul freigegeben oder neu zugeordnet werden.

Betrachten Sie das folgende Beispiel, um dies zu veranschaulichen:

  • .EXE ist mit MSVCRT verknüpft. BEFREIEN
  • DLL A ist mit LIBCMT verknüpft. BEFREIEN
  • DLL B ist mit CRTDLL verknüpft. BEFREIEN

Wenn der .EXE ein CRT-Dateihandle mit _create() oder erstellt, kann dieses Dateihandle nur an _lseek()die datei .EXE übergeben werden. _close()_read()_write()_open() Übergeben Sie dieses CRT-Dateihandle nicht an eine der DLL-Dateien. Übergeben Sie kein CRT-Dateihandle, das von der DLL an die andere DLL oder an die .EXE abgerufen wurde.

Wenn DLL A einen Speicherblock zuweist malloc(), kann nur DLL A aufrufen free(), _expand()oder realloc() um diesen Block zu betreiben. Sie können nicht von DLL A aufrufen malloc() und versuchen, diesen Block aus dem .EXE oder von DLL B frei zu geben.

Notiz

Wenn alle drei Module mit CRTDLL verknüpft wurden. LIB oder alle drei wurden mit MSVCRT verknüpft. LIb, diese Einschränkungen würden nicht gelten.

Beim Verknüpfen von DLLs mit LIBC. LIB, beachten Sie, dass, wenn es eine möglichkeit gibt, dass eine solche DLL von einem Multithread-Programm aufgerufen wird, die DLL nicht mehrere Threads unterstützt, die gleichzeitig in der DLL ausgeführt werden, was zu großen Problemen führen kann. Wenn es eine Möglichkeit gibt, dass die DLL von Multithread-Programmen aufgerufen wird, stellen Sie sicher, dass Sie sie mit einer der Bibliotheken verknüpfen, die Multithread-Programme (LIBCMT) unterstützen. LIB, CRTDLL. LIB oder MSVCRT. LIB).