Поделиться через


Использование времени выполнения C

В этой статье описывается использование времени выполнения C.

Исходная версия продукта: Visual C++
Исходный номер базы знаний: 94248

Раздел 1. Доступны три формы библиотек времени выполнения C (CRT)

Существует три формы библиотеки времени выполнения C, предоставляемые пакетом SDK для Win32:

  • LIBC. LIB — это статическая связанная библиотека для однопоточных программ.

  • LIBCMT. LIB — это статическая связанная библиотека, которая поддерживает многопоточные программы.

  • CRTDLL. LIB — это библиотека импорта для CRTDLL.DLL, которая также поддерживает многопоточные программы. CRTDLL.DLL сама является частью Windows NT.

Microsoft Visual C++ 32-разрядного выпуска также содержит эти три формы, однако CRT в библиотеке DLL называется MSVCRT. LIB. Библиотека DLL распространяется. Его имя зависит от версии VC++ (то есть MSVCRT10.DLL или MSVCRT20.DLL). Обратите внимание, что MSVCRT10.DLL не поддерживается в Win32s, а CRTDLL. LIB поддерживается в Win32s. MSVCRT20.DLL поставляется в двух версиях: одна для Windows NT и другая для Win32s.

Раздел 2. Использование библиотек CRT при создании библиотек DLL

При создании библиотеки DLL, которая использует любую из библиотек времени выполнения C, чтобы убедиться, что CRT правильно инициализирована, либо

  1. Функция инициализации должна быть названа DllMain() , а точка входа должна быть указана с параметром компоновщика. -entry:_DllMainCRTStartup@12

    or

  2. Точка входа библиотеки DLL должна явно вызывать CRT_INIT() подключение процесса и отсоединение процесса.

Это позволяет библиотекам времени выполнения C правильно выделять и инициализировать данные времени выполнения C, когда процесс или поток присоединяется к библиотеке DLL, правильно очищать данные времени выполнения C, когда процесс отсоединяется от библиотеки DLL, а также для глобальных объектов C++ в библиотеке DLL, которые должны быть правильно созданы и деструкированы.

Примеры пакета SDK Win32 используют первый метод. Используйте их в качестве примера. Также ознакомьтесь со справочником DllEntryPoint() программиста Win32 и документацией DllMain()по Visual C++. Обратите внимание, что DllMainCRTStartup() вызовы и CRT_INIT() вызовут CRT_INIT() библиотеку DllMain() приложения, если она существует.

Если вы хотите использовать второй метод и вызвать код инициализации CRT самостоятельно, вместо использования DllMainCRTStartup() и DllMain()есть два метода:

  1. Если нет функции входа, выполняющей код инициализации, укажите CRT_INIT() в качестве точки входа библиотеки DLL. Предположим, что вы включили NTWIN32. MAK, который определяется DLLENTRY как @12, добавьте параметр в строку ссылки библиотеки DLL:-entry:_CRT_INIT$(DLLENTRY).

    or

  2. Если у вас есть собственная точка входа DLL, выполните указанные ниже действия в точке входа:

    1. Используйте этот прототип для CRT_INIT(): BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);

      Сведения о CRT_INIT() возвращаемых значениях см. в документации DllEntryPoint. Возвращаются те же значения.

    2. В DLL_PROCESS_ATTACH и DLL_THREAD_ATTACH (см. раздел DllEntryPoint в справочнике по API Win32 для получения дополнительных сведений об этих флагах), вызов , сначала перед вызовом CRT_INIT()любых функций во время выполнения C или любых операций с плавающей запятой.

    3. Вызовите собственный код процесса, инициализации потока и завершения.

    4. После DLL_PROCESS_DETACH вызова всех функций времени выполнения C и DLL_THREAD_DETACHпоследнего вызова CRT_INIT() все операции с плавающей запятой завершаются.

Обязательно передайте CRT_INIT() все параметры точки входа; CRT_INIT() ожидает эти параметры, поэтому вещи могут не работать надежно, если они опущены (в частности, fdwReason требуется для определения необходимости инициализации процесса или завершения).

Ниже приведена схема функции точки входа, показывающая, когда и как выполнять эти вызовы CRT_INIT() в точке входа DLL:

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

Примечание.

Это не обязательно, если вы используете DllMain() и -entry:_DllMainCRTStartup@12.

Раздел 3. Использование NTWIN32. MAK для упрощения процесса сборки

В NTWIN32 определены макросы. MAK, который можно использовать для упрощения файлов makefile и обеспечения правильности их создания, чтобы избежать конфликтов. По этой причине корпорация Майкрософт настоятельно рекомендует использовать 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, ссылается на библиотеку DLL, которая также вызывает вызовы времени выполнения C, следует помнить, что если они связаны с одной из статически связанных библиотек времени выполнения C (LIBC). LIB или LIBCMT. LIB), .EXE и DLL будут иметь отдельные копии всех функций времени выполнения C и глобальных переменных. Это означает, что данные времени выполнения C нельзя совместно использовать между .EXE и библиотекой DLL. Ниже приведены некоторые проблемы, которые могут возникнуть в результате:

  • Передача буферных дескрипторов потока из .EXE/DLL в другой модуль

  • Выделение памяти при вызове времени выполнения C в .EXE/DLL и перераспределении или освобождении его в другом модуле

  • Проверка или установка значения глобальной переменной errno в .EXE/DLL и ожидании того, что она будет той же в другом модуле. Связанная проблема вызывается perror() в противоположном модуле, из которого произошла ошибка времени выполнения C, так как perror() использует errno.

Чтобы избежать этих проблем, свяжите .EXE и БИБЛИОТЕКу DLL с CRTDLL. LIB или MSVCRT. LIB, который позволяет .EXE и DLL использовать общий набор функций и данных, содержащихся в CRT в библиотеке DLL, и данные времени выполнения C, такие как дескриптор потоков, можно использовать как .EXE, так и библиотеку DLL.

Раздел 5. Сочетание типов библиотек

Вы можете связать библиотеку DLL с CRTDLL. LIB/MSVCRT. LIB независимо от того, с каким .EXE связана ваша .EXE, если не следует смешивать структуры данных CRT и передавать дескрипторы CRT-файлов или указатели CRT FILE* на другие модули.

При перемешивание типов библиотек соответствует следующим:

  • Дескриптора файлов CRT могут работать только с помощью модуля CRT, созданного им.

  • Указатели CRT FILE* могут работать только с помощью модуля CRT, создавшего их.

  • Память, выделенная функцией malloc() CRT, может быть освобождена или перераспределирована модулем CRT, выделенным им.

Чтобы проиллюстрировать это, рассмотрим следующий пример:

  • .EXE связан с MSVCRT. LIB
  • Библиотека DLL A связана с LIBCMT. LIB
  • БИБЛИОТЕКА DLL B связана с CRTDLL. LIB

Если .EXE создает дескриптор файла CRT с помощью _create() или _open()этот дескриптор файла может передаваться _lseek()только в , _read(), _write()и _close()т. д. в файле .EXE. Не передайте этот дескриптор CRT-файла в библиотеку DLL. Не передайте дескриптор CRT-файла, полученный из библиотеки DLL в другую библиотеку DLL или в .EXE.

Если БИБЛИОТЕКА DLL A выделяет блок памяти с malloc()помощью вызова только библиотеки DLL A free()_expand()или realloc() для работы с этим блоком. Невозможно вызвать malloc() библиотеку DLL A и попытаться освободить этот блок из .EXE или из библиотеки DLL B.

Примечание.

Если все три модуля были связаны с CRTDLL. LIB или все три были связаны с MSVCRT. Эти ограничения не применяются.

При связывании библиотек DLL с LIBC. Обратите внимание, что если такая библиотека DLL будет вызываться многопоточной программой, библиотека DLL не будет поддерживать несколько потоков, выполняемых в библиотеке DLL одновременно, что может привести к серьезным проблемам. Если существует вероятность того, что библиотека DLL будет вызываться многопоточной программой, обязательно свяжите ее с одной из библиотек, поддерживающих многопоточные программы (LIBCMT). LIB, CRTDLL. LIB или MSVCRT. LIB).