Общие сведения о возможных проблемах, возникающих при обновлении (Visual C++)

За прошедшие годы компилятор Microsoft C++ претерпел множество изменений, кроме того, изменения были внесены и в сам язык C++, стандартную библиотеку C++, среду выполнения C (CRT) и другие библиотеки, например MFC и ATL. В результате при обновлении приложения из более ранней версии Visual Studio могут появиться ошибки компилятора и компоновщика и предупреждения в коде, ранее скомпилированном ранее. Чем старше исходная база кода, тем больше вероятность таких ошибок. В этом обзоре приведены наиболее распространенные классы проблем, которые вы можете увидеть, и содержит ссылки на более подробные сведения.

Примечание.

В прошлом мы рекомендовали, чтобы обновления, охватывающие несколько версий Visual Studio, выполнялись постепенно по одной версии. Однако теперь это не так. Мы обнаружили, что почти всегда проще обновить до самой последней версии Visual Studio независимо от того, насколько старой базой кода.

Вопросы и комментарии о процессе обновления можно отправить на адрес vcupgrade@microsoft.com.

Зависимости библиотек и наборов средств

Примечание.

Этот раздел относится к приложениям и библиотекам, созданным с помощью Visual Studio 2013 и более ранних версий. Наборы средств, используемые в Visual Studio 2015, Visual Studio 2017 и Visual Studio 2019, совместимы на уровне двоичного кода. Дополнительные сведения см. в статье О совместимости двоичных файлов C++ между версиями Visual Studio.

При обновлении приложения с Visual Studio 2013 или до более новой версии часто рекомендуется и необходимо обновить все библиотеки и библиотеки DLL, на которые ссылается приложение. Либо у вас должен быть доступ к исходному коду, либо поставщик библиотеки должен предоставить новые двоичные файлы, скомпилированные с той же основной версией компилятора. Если одно из этих условий соблюдено, можете пропустить данный раздел со сведениями о совместимости двоичных данных. Если это не так, библиотеки могут не работать в обновленном приложении. Сведения в этом разделе помогут понять, можно ли продолжить обновление.

Набор инструментов

.obj.lib Форматы файлов хорошо определены и редко изменяются. Иногда в них вносятся дополнения, однако они обычно не препятствуют использованию объектных файлов и библиотек, созданных в более старых наборах инструментов. Основное исключение заключается в компиляции с помощью /GL (оптимизация программы Кто le). При компиляции с помощью /GLможно связать только полученный файл объекта с помощью того же набора инструментов, который использовался для его создания. Таким образом, если вы создаете файл объекта и /GL используете компилятор Visual Studio 2017 (v141), необходимо связать его с помощью компоновщика Visual Studio 2017 (v141). Это связано с тем, что внутренние структуры данных в файлах объектов не стабильны в основных версиях набора инструментов. Новые наборы инструментов не понимают старые форматы данных.

У C++ нет стабильного двоичного интерфейса приложений (ABI). Visual Studio предоставляет стабильный ABI C++ для всех дополнительных номеров версий выпуска. Наборы инструментов Visual Studio 2015 (версии 140), Visual Studio 2017 (версии 141), Visual Studio 2019 (v142) и Visual Studio 2022 (v143) зависят только в их дополнительной версии. Все они имеют тот же номер основной версии — 14. Дополнительные сведения см. в статье О совместимости двоичных файлов C++ между версиями Visual Studio.

Объектный файл, содержащий внешние символы с компоновкой C++, может неправильно связываться с объектными файлами, созданными с помощью другого основного номера версии набора инструментов. Существует множество возможных результатов: ссылка может завершиться ошибкой (например, если украшение имени изменилось). Ссылка может завершиться успешно, но приложение может завершиться ошибкой во время выполнения (например, если макеты типов изменились). Или ваше приложение может продолжать работать, и ничего не пойдет не так. Кроме того, хотя ABI C++ не является стабильным, ABI C и подмножество ABI C++, необходимое для COM, являются стабильными.

При компоновке с библиотекой импорта любые более поздние версии библиотек распространяемых компонентов Visual Studio, которые сохраняют совместимость с ABI, можно использовать во время выполнения. Например, при компиляции и связывании приложения с помощью набора инструментов Visual Studio 2015 с обновлением 3 можно использовать любой более поздний распространяемый набор. Это связано с тем, что библиотеки 2015, 2017, 2019 и 2022 года сохранили обратную совместимость двоичных файлов. Обратный вариант не имеет значения true: вы не можете использовать распространяемый компонент для более ранней версии набора инструментов, чем вы использовали для сборки любого компонента кода.

Библиотеки

Если вы #include используете определенную версию файлов заголовков, необходимо связать результирующий файл объекта с той же версией библиотек. Например, если исходный файл содержит Visual Studio 2015 с обновлением 3 <immintrin.h>, необходимо связаться с библиотекой Visual Studio 2015 с обновлением 3 vcruntime . Аналогичным образом, если исходный файл включает Visual Studio 2017 версии 15.5 <iostream>, необходимо связаться с библиотекой msvcprtVisual Studio 2017 версии 15.5 Standard C++ . Сочетание и сопоставление не поддерживается.

Для стандартной библиотеки C++ использование стандартных заголовков с Visual Studio 2010 явно запрещено #pragma detect_mismatch . Если вы пытаетесь связать несовместимые файлы объектов или при связывании с неправильной стандартной библиотекой ссылка завершается ошибкой.

Более старая версия CRT смешивания и сопоставления никогда не поддерживается, но часто она просто работала, так как поверхность API не менялась много с течением времени. В универсальной CRT такая обратная совместимость была нарушена, чтобы мы могли обеспечивать обратную совместимость в будущем. В будущем у нас нет планов ввести новые, версии универсальных двоичных файлов CRT. Вместо этого существующая универсальная CRT теперь обновляется на месте.

Для обеспечения частичной совместимости ссылок с файлами объектов (и библиотеками), скомпилированных с более старыми версиями заголовков среды выполнения Microsoft C, мы предоставляем библиотеку legacy_stdio_definitions.libс Visual Studio 2015 и более поздними версиями. Эта библиотека содержит символы совместимости для большинства функций и экспортов данных, которые были удалены из универсальной CRT. Набор символов совместимости, предоставляемых legacy_stdio_definitions.lib достаточно для удовлетворения большинства зависимостей, включая все зависимости в библиотеках, включенных в пакет SDK для Windows. Однако некоторые символы были удалены из универсальной CRT, у которых нет символов совместимости. Эти символы включают как некоторые функции (например, __iob_funcтак и некоторые экспорты данных) (например, __imp___iob, __imp___pctype). __imp___mb_cur_max

Если у вас есть статическая библиотека, созданная с помощью более старой версии заголовков среды выполнения C, рекомендуется выполнить следующие действия в следующем порядке:

  1. Перестройте статическую библиотеку с помощью новой версии Visual Studio и заголовков универсальной CRT, чтобы обеспечить поддержку компоновки с универсальной CRT. Этот подход полностью поддерживается и оптимальный вариант.

  2. Если вы не можете (или не хотите) перестроить статическую библиотеку, попробуйте связаться с legacy_stdio_definitions.libней. Если она удовлетворяет зависимостям времени ссылки статической библиотеки, необходимо тщательно проверить статическую библиотеку, так как она используется в двоичном файле. Убедитесь, что это не негативно влияет на какие-либо изменения поведения, внесенные в универсальную CRT.

  3. Возможно, зависимости статической библиотеки не удовлетворены legacy_stdio_definitions.lib или библиотека не работает с универсальной CRT из-за изменений поведения. В этом случае рекомендуется инкапсулировать статическую библиотеку в библиотеку DLL, связанную с требуемой версией среды выполнения Microsoft C. Например, если статическая библиотека была создана с помощью Visual Studio 2013, создайте эту библиотеку DLL с помощью набора инструментов Visual Studio 2013 и библиотек C++. Встроив библиотеку в библиотеку DLL, вы инкапсулируете сведения о реализации, представляющие ее зависимость от определенной версии среды выполнения Microsoft C. Будьте осторожны с интерфейсом DLL не утечь сведения о том, какую среду выполнения C она использует, например, если она возвращает FILE* границу БИБЛИОТЕКи DLL или mallocвыделенный указатель вызывающего объекта.free

Использование нескольких crT в одном процессе не является проблематичным. (На самом деле большинство процессов загружают несколько БИБЛИОТЕК DLL CRT. Например, компоненты операционной системы Windows зависят msvcrt.dllот , и среда CLR зависит от собственного частного CRT.) Проблемы возникают при перемыкающем состоянии из разных CRT. Например, вы не должны выделять память с помощью msvcr110.dll!mallocmsvcr120.dll!freeи пытаться освободить эту память, используя ее, и не следует пытаться открыть файл с помощью msvcr110!fopen и попытаться считывать из этого ФАЙЛА.msvcr120!fread Если вы не хватите состояние из разных crT, вы можете безопасно загрузить несколько CRT в одном процессе.

Дополнительные сведения см. в разделе Обновление кода для универсальной среды выполнения C.

Ошибки, вызванные параметрами проекта

Чтобы начать процесс обновления, откройте старую версию проекта, решения или рабочей области в последней версии Visual Studio. Visual Studio создаст новый проект на основе старых параметров проекта. Проверьте, имеет ли старый проект пути библиотеки или пути, которые жестко закодируются в нестандартном расположении. Возможно, файлы в этих путях не будут видны компилятору, когда проект использует параметры по умолчанию. Дополнительные сведения см. в разделе Параметр OutputFile компоновщика.

Как правило, теперь отличное время упорядочивать код проекта, чтобы упростить обслуживание проекта и помочь вам максимально быстро создать обновленный код. Если исходный код уже хорошо упорядочен, а старый проект компилируется в Visual Studio 2010 или более поздней версии, вы можете вручную изменить новый файл проекта для поддержки компиляции как старого, так и нового компилятора. Следующий пример демонстрирует компиляцию для Visual Studio 2015 и Visual Studio 2017:

<PlatformToolset Condition="'$(VisualStudioVersion)'=='14.0'">v140</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>

LNK2019: неразрешенные внешние элементы

Для неразрешенных символов вам может потребоваться исправить параметры проекта.

  • Если исходный файл находится в расположении, отличном от по умолчанию, вы добавили путь к каталогам включаемых проектов?

  • Если внешний определен в .lib файле, вы указали путь lib в свойствах проекта и правильно ли версию файла, расположенного .lib там?

  • Вы пытаетесь связаться с файлом .lib , скомпилированным с другой версией Visual Studio? Если это так, см. предыдущий раздел о зависимостях наборов инструментов и библиотек.

  • Типы аргументов в месте вызова соответствуют существующей перегрузке функции? Убедитесь, что базовые типы являются ожидаемыми, как для всех типов в сигнатуре функции, так и в коде, который вызывает функцию.

Чтобы устранить неразрешенные ошибки символов, можно использовать dumpbin.exe для проверки символов, определенных в двоичном файле. Попробуйте выполнить следующую команду для просмотра символов, определенных в библиотеке:

dumpbin.exe /LINKERMEMBER somelibrary.lib

/Zc:wchar_t (wchar_t собственный тип)

(В Microsoft Visual C++ 6.0 и более ранних wchar_t версиях не реализован в виде встроенного типа. Она была объявлена в wchar.h качестве типа для unsigned short.) Для стандарта C++ требуется wchar_t встроенный тип. Использование версии определения типа может вызывать проблемы переносимости. Если вы обновляете более ранние версии Visual Studio и видите ошибку компилятора C2664, так как код пытается неявно преобразовать в wchar_tunsigned short, рекомендуется изменить код, чтобы устранить ошибку, а не задать параметр /Zc:wchar_t-. Дополнительные сведения см. в разделе /Zc:wchar_t (wchar_t собственный тип).

Обновление с параметрами /NODEFAULTLIBкомпоновщика и /ENTRY/NOENTRY

Параметр /NODEFAULTLIB компоновщика (или свойство компоновщика "Игнорировать все библиотеки по умолчанию") сообщает компоновщику не автоматически связываться в библиотеках по умолчанию, таких как CRT. Это означает, что каждую библиотеку нужно отдельно указать в качестве входных данных. Этот список библиотек представлен в свойстве Дополнительные зависимости в разделе Компоновщик диалогового окна Свойства проекта.

Проекты, использующие этот параметр, вызывают проблемы при обновлении, связанные с рефакторингом содержимого некоторых библиотек по умолчанию. Так как требуется указать каждую библиотеку в свойстве Дополнительные зависимости или в командной строке компоновщика, нужно обновить список библиотек, чтобы использовать все актуальные имена.

В следующей таблице приведены библиотеки, содержимое которых было изменено начиная с Visual Studio 2015. Для обновления нужно добавить новые имена библиотек во второй столбец к библиотекам в первом столбце. Некоторые из этих библиотек являются библиотеками импорта, но это не должно иметь значения.

При использовании: Вам потребуется использовать следующие библиотеки:
libcmt.lib libcmt.lib, libucrt.lib, libvcruntime.lib
libcmtd.lib libcmtd.lib, libucrtd.lib, libvcruntimed.lib
msvcrt.lib msvcrt.lib, ucrt.lib, vcruntime.lib
msvcrtd.lib msvcrtd.lib, ucrtd.lib, vcruntimed.lib

Аналогичная проблема возникает и при использовании параметра /ENTRY или /NOENTRY, которые также позволяют обойти библиотеки по умолчанию.

Ошибки, вызванные улучшенным соответствием языка

Доработка компилятора Microsoft C++, призванная улучшить его соответствие стандарту C++, ведется уже много лет. Код, скомпилированный в более ранних версиях, может не скомпилироваться в более поздних версиях Visual Studio. Это связано с тем, что компилятор правильно помечает ошибку, которую он ранее проигнорировал или явным образом разрешен.

Например, параметр /Zc:forScope появился в MSVC уже очень давно. Он разрешает несоответствующее поведение для переменных цикла. Теперь этот параметр является нерекомендуемым и может быть удален в будущих версиях. Настоятельно рекомендуется не использовать этот параметр при обновлении кода. Дополнительные сведения см/Zc:forScope-. в нерекомендуемом.

Одним из примеров распространенных ошибок компилятора, с которыми можно столкнуться при обновлении, является передача неконстантного аргумента в константный параметр. Старые версии компилятора не всегда помечают его как ошибку. Дополнительные сведения см. в разделе Более строгие преобразования компилятора.

Дополнительные сведения о конкретных улучшениях соответствия см. в разделах Журнал изменений Visual C++ 2003–2015 и Улучшения соответствия C++ в Visual Studio.

Ошибки, <stdint.h> связанные с целыми типами

Заголовок <stdint.h> определяет typedefs и макросы, которые, в отличие от встроенных целочисленных типов, гарантированно имеют указанную длину на всех платформах. Примеры: uint32_t и int64_t. Заголовок <stdint.h> добавлен в Visual Studio 2010. Код, написанный до 2010 г., мог бы предоставить частные определения для этих типов. И эти определения могут не всегда соответствовать определениям <stdint.h> .

Если ошибка имеет значение C2371, а stdint тип связан, скорее всего, это означает, что тип определен в заголовке кода или в файле сторонней библиотеки. При обновлении следует исключить любые пользовательские определения типов, но сначала сравнить пользовательские определения <stdint.h> с текущими стандартными определениями, чтобы не вводить новые проблемы.

Вы можете нажать клавишу F12 (Перейти к определению), чтобы узнать, где определен соответствующий тип.

Здесь /showIncludes можно использовать параметр компилятора. В диалоговом окне "Страницы свойств" проекта выберите страницу "Свойства>конфигурации C/C++>Advanced" и установите для параметра "Показать включает" значение "Да". Затем перестройте проект. Вы увидите список #include файлов в окне вывода. Каждый заголовок отображается с отступом под тем заголовком, который включает его.

Ошибки, связанные с функциями CRT

За прошедшие годы в среду выполнения C было внесено множество изменений. Были добавлены многие безопасные версии функций, а некоторые были удалены. Кроме того, как описано ранее в этой статье, реализация CRT майкрософт была рефакторинговой в Visual Studio 2015 в новые двоичные файлы и связанные .lib файлы.

Если ошибка связана с функцией CRT, обратитесь к разделу Журнал изменений Visual C++ 2003–2015 или Улучшения соответствия C++ в Visual Studio для поиска дополнительной информации. Если ошибка LNK2019, убедитесь, что функция не удалена. В противном случае, если вы уверены, что функция по-прежнему существует, и вызывающий код является правильным, проверка, чтобы узнать, используется /NODEFAULTLIBли проект. В этом случае необходимо обновить список библиотек для использования новых универсальных библиотек (UCRT). Дополнительные сведения см. в разделе о библиотеках и зависимостях выше.

Если ошибка включает в себя printf или scanfубедитесь, что вы не определяете ни функцию, ни в том случае, если она не включается stdio.h. Если да, удалите частные определения или ссылку на legacy_stdio_definitions.lib. Эту библиотеку можно указать в свойстве Дополнительные зависимости, находящемся в разделе Свойства конфигурации>Компоновщик>Входные данные диалогового окна Страницы свойств. Если вы связываетесь с Windows SDK 8.1 или более ранней версией, добавьте legacy_stdio_definitions.lib.

Если ошибка связана с аргументами строки форматирования, вероятно, это вызвано тем, что компилятор строже соответствует стандарту. Дополнительные сведения см. в журнале изменений. Отнеситесь к указанным здесь ошибкам с особым вниманием, так как они могут представлять угрозу безопасности.

Ошибки, вызванные изменениями в стандарте C++

Сам стандарт C++ развивался способами, которые не всегда являются обратно совместимыми. C++11 представила семантику перемещения, новые ключевое слово и другие функции языка и стандартной библиотеки. Эти изменения могут вызвать ошибки компилятора и даже другое поведение среды выполнения.

Например, старая программа C++ может включать iostream.h заголовок. Этот заголовок C++ был признан нерекомендуемым уже довольно давно и был полностью удален из Visual Studio. В этом случае необходимо использовать <iostream> и перезаписать код. Дополнительные сведения см. в разделе "Обновление старого iostream кода".

C4838: предупреждение о сужающих преобразованиях

Стандарт C++ теперь указывает, что преобразования из без знака в подписанные целочисленные значения являются сужающими преобразованиями. Компилятор не вызвал это предупреждение до Visual Studio 2015. Проверьте каждое вхождение, чтобы убедиться, что сужение не влияет на правильность кода.

Предупреждения об использовании безопасных функций CRT

Постепенно стали появляться безопасные версии функций для среды выполнения C. Хотя старые небезопасные версии по-прежнему доступны, рекомендуется изменить код, чтобы использовать безопасные версии. При наличии небезопасных версий компилятор выдает предупреждение. Вы можете отключить или игнорировать эти предупреждения. Чтобы отключить предупреждения для всех проектов в решении, откройте Вид>Диспетчер свойств, выберите все проекты, для которых требуется отключить предупреждения, а затем щелкните эти элементы правой кнопкой мыши и выберите Свойства. В разделе Свойства конфигурации>C/C++>Дополнительно диалогового окна Страницы свойств выберите Отключить некоторые предупреждения. Щелкните стрелку раскрывающегося списка и нажмите кнопку "Изменить". Введите 4996 в текстовом поле. (Не включайте префикс C.) Дополнительные сведения см. в статье "Перенос" для использования Secure CRT.

Ошибки, вызванные изменениями в API Windows или устаревшими пакетами SDK

Со временем в среду добавлялись новые API Windows и типы данных, а также изменялись или удалялись уже существующие. Кроме того, другие пакеты SDK, которые не принадлежали основной операционной системе, пришли и исчезли. Старые программы могут содержать вызовы API, которые больше не существуют. Они также могут содержать вызовы API в других пакетах SDK Майкрософт, которые больше не поддерживаются. Вы можете увидеть ошибки, связанные с отсутствием API Или API Windows из старых пакетов SDK Майкрософт. Возможно, API были удалены или заменены более новыми, более безопасными функциями.

Документация по API Windows содержит список минимальных или максимальных поддерживаемых операционных систем. Дополнительные сведения об определенном API Windows см. в индексе API для классических приложений Windows.

Версия Windows

При обновлении программы, которая использует API Windows напрямую или косвенно, необходимо решить минимальную версию Windows для поддержки. В большинстве случаев оптимальным выбором является Windows 7. Дополнительные сведения см. в разделе Проблемы с файлами заголовков. Макрос WINVER определяет самую старую версию Windows, в которой ваша программа может выполняться. Если программа MFC задает WINVER значение 0x0501 (Windows XP), вы получите предупреждение, так как MFC больше не поддерживает XP, даже если набор инструментов компилятора имеет режим XP. Поддержка набора инструментов компилятора для Windows XP закончилась в Visual Studio 2017.

Дополнительные сведения см. в разделе Об обновлении целевой версии Windows и более устаревших файлов заголовков.

ATL/MFC

ATL и MFC являются относительно стабильными API, однако и в них периодически вносятся изменения. Дополнительные сведения см. в статье журнал изменений Visual C++ 2003 – 2015, новые возможности visual C++ в Visual Studio и улучшения соответствия C++ в Visual Studio.

LNK 2005 _DllMain@12 уже определен в MSVCRTD.lib

Эта ошибка может возникать в приложениях MFC. Она указывает на проблему очередности между библиотекой CRT и библиотеки MFC. MFC сначала должен быть связан таким образом, чтобы он предоставлял new и delete операторы. Чтобы устранить ошибку /NODEFAULTLIB , используйте переключатель, чтобы игнорировать эти библиотеки по умолчанию: MSVCRTD.lib и mfcs140d.lib. Затем добавьте эти же библиотеки в качестве дополнительных зависимостей.

32-разрядные и 64-разрядные версии

Если исходный код компилируется для 32-разрядных систем, вы можете создать 64-разрядную версию вместо (или в дополнение) к новому 32-разрядному приложению. В общем случае следует сначала скомпилировать программу в 32-разрядном режиме, а затем попробовать 64-разрядный режим. Компиляция в 64-разрядном режиме не вызывает трудностей, однако в некоторых случаях может выявлять ошибки, скрытые в 32-разрядных сборках.

Кроме того, следует учитывать возможные проблемы со временем компиляции и средой выполнения, касающиеся размера указателя, значений времени и размера, а также описателей printfscanf формата и функций. Дополнительные сведения см. в статье "Настройка Visual C++ для 64-разрядных целевых объектов x64 и распространенных проблем миграции Visual C++ с 64-разрядной версией. Дополнительные советы по миграции см . в руководстве по программированию для 64-разрядной версии Windows.

Юникод и MBCS/ASCII

До стандартизации Юникода многие программы использовали многобайтовый набор символов (МБ CS) для представления символов, которые не были включены в набор символов ASCII. В старых проектах MFC МБ CS был параметром по умолчанию. При обновлении такой программы вы увидите предупреждения, которые советуют использовать Юникод. Если вы решите, что преобразование в Юникод не стоит затрат на разработку, вы можете отключить или игнорировать предупреждение. Чтобы отключить его для всех проектов в решении, откройте Вид>Диспетчер свойств, выберите все проекты, для которых требуется отключить предупреждения, а затем щелкните эти элементы правой кнопкой мыши и выберите Свойства. В диалоговом окне Страницы свойств выберите Свойства конфигурации>C/C++>Дополнительно. Откройте раскрывающийся список в свойстве Отключить некоторые предупреждения и выберите Изменить. Введите 4996 в текстовом поле. (Не включайте префикс C.) Нажмите кнопку "ОК", чтобы сохранить свойство, а затем нажмите кнопку "ОК", чтобы сохранить изменения.

Дополнительные сведения см. в разделе Перенос из MBCS в Юникод. Общие сведения о МБ CS и Юникоде см. в разделе "Текст и строки" в Visual C++ и internationalization.

См. также

Обновление проектов с более ранних версий Visual C++
Улучшения соответствия C++ в Visual Studio