Översikt över potentiella uppgraderingsproblem (Microsoft C++)

Under årens lopp har Microsoft C++ -kompilatorn (MSVC) genomgått många ändringar, tillsammans med ändringar i själva C++-språket, C++ Standard Library (STL), C-körningen (CRT) och andra bibliotek som MFC och ATL. När du uppgraderar ett program från en tidigare version av Visual Studio kan du därför se kompilator- och länkfel och varningar i kod som tidigare kompilerats rent. Ju äldre den ursprungliga kodbasen är, desto större är risken för sådana fel. Den här översikten sammanfattar de vanligaste klasserna av problem som du sannolikt kommer att se och innehåller länkar till mer detaljerad information.

Anmärkning

Tidigare har vi rekommenderat att uppgraderingar som omfattar flera versioner av Visual Studio ska utföras stegvis en version i taget. Vi rekommenderar inte längre den här metoden. Vi har upptäckt att det nästan alltid är enklare att uppgradera till den senaste versionen av Visual Studio oavsett hur gammal kodbasen är.

Frågor eller kommentarer om uppgraderingsprocessen kan skickas till vcupgrade@microsoft.com.

Beroenden för biblioteks- och byggverktyg

Anmärkning

Det här avsnittet gäller för program och bibliotek som skapats med Visual Studio 2013 och tidigare. De byggverktyg som används i Visual Studio 2015, Visual Studio 2017 och Visual Studio 2019 är binärkompatibla. Mer information finns i C++ Binär kompatibilitet mellan Visual Studio-versioner.

När du uppgraderar en app från Visual Studio 2013 eller tidigare till en nyare version är det ofta både lämpligt och nödvändigt att uppgradera alla bibliotek och DLL:er som appen länkar till. Antingen måste du ha åtkomst till källkoden, eller så måste biblioteksleverantören tillhandahålla nya binära filer som kompilerats med samma huvudversion av kompilatorn. Om något av dessa villkor är sant kan du hoppa över det här avsnittet, som behandlar information om binär kompatibilitet. Om så inte är fallet kanske biblioteken inte fungerar i din uppgraderade app. Informationen i det här avsnittet hjälper dig att förstå om du kan fortsätta med uppgraderingen.

Byggverktyg

Filformaten .obj och .lib är väldefinierade och ändras sällan. Ibland görs tillägg i dessa filformat, men dessa tillägg påverkar vanligtvis inte möjligheten för nyare byggverktyg att använda objektfiler och bibliotek som skapats av äldre byggverktyg. Det största undantaget är om du kompilerar med hjälp av /GL (Hela programoptimering). Om du kompilerar med /GLkan du bara länka den resulterande objektfilen med hjälp av samma byggverktyg som användes för att skapa den. Om du skapar en objektfil med /GL och använder en Visual Studio 2017-kompilator (v141) måste du länka den med hjälp av Visual Studio 2017-länkaren (v141). Det beror på att de interna datastrukturerna i objektfilerna inte är stabila i större versioner av byggverktygen. Nyare byggverktyg förstår inte de äldre dataformaten.

C++ har inget stabilt binärt programgränssnitt (ABI). Men Visual Studio har en stabil C++ ABI för alla mindre versioner av en version. Visual Studio 2015 (v140), Visual Studio 2017 (v141), Visual Studio 2019 (v142), Visual Studio 2022 (v143) och Visual Studio 2026 (v145) byggverktyg skiljer sig endast åt i sina delversioner. De har alla samma huvudversionsnummer, vilket är 14. Mer information finns i C++ Binär kompatibilitet mellan Visual Studio-versioner.

Om du har en objektfil som har externa symboler med C++-länkning kanske objektfilen inte länkar korrekt till objektfiler som skapats av en annan huvudversion av byggverktygen. Det finns många möjliga resultat: länken kan misslyckas helt (till exempel om namndekorationen har ändrats). Länken kan lyckas, men appen kan misslyckas vid körning (till exempel om typlayouter har ändrats). Eller så kan din app fortsätta att fungera och ingenting kommer att gå fel. Observera också att även om C++ ABI inte är stabilt är C ABI och delmängden av C++ ABI som krävs för COM stabila.

Om du länkar till ett importbibliotek kan alla senare versioner av Visual Studio-omdistribuerbara bibliotek som bevarar ABI-kompatibilitet användas vid körning. Om du till exempel kompilerar och länkar din app med hjälp av versionsverktygen för Visual Studio 2015 Update 3 kan du använda vilken som helst senare version av en omdistribuerbar komponent. Det beror på att biblioteken 2015, 2017, 2019, 2022 och 2026 har bevarat bakåt binär kompatibilitet. Det omvända är inte sant: Du kan inte använda en återdistribuerbar för en tidigare version av byggverktygen än du använde för att bygga någon komponent av din kod.

Bibliotek

Om du #include har en viss version av huvudfilerna måste du länka den resulterande objektfilen till samma version av biblioteken. Om källfilen till exempel innehåller Visual Studio 2015 Update 3 <immintrin.h>måste du länka till Visual Studio 2015 Update 3-biblioteket vcruntime . Om källfilen på samma sätt innehåller Visual Studio 2017 version 15.5 <iostream>måste du länka till Visual Studio 2017 version 15.5 Standard C++-biblioteket, msvcprt. Blandning och matchning stöds inte.

För Microsoft C++ Standard Library (STL) har blandning och matchning uttryckligen nekats genom användning av #pragma detect_mismatch i standardrubrikerna sedan Visual Studio 2010. Om du försöker länka inkompatibla objektfiler, eller om du länkar till fel standardbibliotek, misslyckas länken.

Äldre CRT-version av blandning och matchning stöddes aldrig, men det fungerade ofta bara eftersom API-ytan inte ändrades mycket över tid. Universal CRT bröt bakåtkompatibiliteten så att vi i framtiden kan upprätthålla bakåtkompatibilitet. Vi har inga planer på att introducera nya, versionerade Universal CRT-binärfiler i framtiden. I stället uppdateras den befintliga universella CRT:en på plats.

För att ge partiell länkkompatibilitet med objektfiler (och bibliotek) som kompilerats med äldre versioner av Microsoft C Runtime-huvuden, tillhandahåller vi ett bibliotek, , legacy_stdio_definitions.libmed Visual Studio 2015 och senare. Det här biblioteket innehåller kompatibilitetssymboler för de flesta funktioner och dataexporter som har tagits bort från den universella CRT:en. Uppsättningen med kompatibilitetssymboler som tillhandahålls av legacy_stdio_definitions.lib är tillräcklig för att uppfylla de flesta beroenden, inklusive alla beroenden i bibliotek som ingår i Windows SDK. Vissa symboler har dock tagits bort från den universella CRT som inte har kompatibilitetssymboler. Dessa symboler innehåller både vissa funktioner (till exempel __iob_func) och vissa dataexporter (till exempel __imp___iob, __imp___pctype, __imp___mb_cur_max).

Om du har ett statiskt bibliotek som skapats med hjälp av en äldre version av C Runtime-huvudena rekommenderar vi följande åtgärder i den här ordningen:

  1. Återskapa det statiska biblioteket med den nya versionen av Visual Studio och universella CRT-huvuden för att stödja länkning med universal-CRT. Den här metoden stöds fullt ut och det bästa alternativet.

  2. Om du inte kan (eller inte vill) återskapa det statiska biblioteket kan du försöka länka med legacy_stdio_definitions.lib. Om det uppfyller länktidsberoendena för ditt statiska bibliotek vill du testa det statiska biblioteket noggrant eftersom det används i binärfilen. Kontrollera att den inte påverkas negativt av någon av de beteendeändringar som har gjorts i universal-CRT.

  3. Beroenden för det statiska biblioteket kanske inte uppfylls av legacy_stdio_definitions.lib eller så fungerar inte biblioteket med den universella CRT:en på grund av beteendeändringar. I det här fallet rekommenderar vi att du kapslar in ditt statiska bibliotek i en DLL som du länkar till den nödvändiga versionen av Microsoft C Runtime. Om det statiska biblioteket till exempel skapades med Visual Studio 2013 skapar du den här DLL:n med hjälp av Visual Studio 2013-kompileringsverktygen och C++-biblioteken. Genom att skapa biblioteket i en DLL kapslar du in den implementeringsinformation som är beroende av en viss version av Microsoft C Runtime. Var försiktig så att DLL-gränssnittet inte läcker information om vilken C Runtime det använder, till exempel om det returnerar en FILE* över DLL-gränsen eller en malloc-allokerad pekare som anroparen måste free.

Användning av flera CRT:er i en enda process är inte i sig problematisk. (I själva verket läser de flesta processer in flera CRT-DLL:er. Till exempel är komponenter i Windows-operativsystemet beroende av msvcrt.dll, och CLR är beroende av sin egen privata CRT.) Problem uppstår när du blandar ihop tillstånd från olika CRTs. Du bör till exempel inte allokera minne med och msvcr110.dll!malloc försöka frigöra minnet med hjälp av msvcr120.dll!free, och du bör inte försöka öppna en FIL med och msvcr110!fopen försöka läsa från filen med hjälp av msvcr120!fread. Så länge du inte blandar ihop status från olika CRT kan du utan problem ha flera CRT:er inlästa i en och samma process.

Mer information finns i Uppgradera din kod till Universal CRT.

Fel som orsakas av projektinställningar

Starta uppgraderingsprocessen genom att öppna ett äldre projekt/en äldre lösning/arbetsyta i den senaste versionen av Visual Studio. Visual Studio skapar ett nytt projekt baserat på de gamla projektinställningarna. Kontrollera om det äldre projektet har bibliotekssökvägar eller innehåller sökvägar som är hårdkodade till platser som inte är standard. Det är möjligt att filerna i dessa sökvägar inte visas för kompilatorn när projektet använder standardinställningarna. Mer information finns i Linker OutputFile-inställningen.

I allmänhet är nu ett bra tillfälle att organisera din projektkod för att förenkla projektunderhållet och få din uppgraderade kod att bygga så snabbt som möjligt. Om källkoden redan är välorganiserad och ditt äldre projekt kompileras under Visual Studio 2010 eller senare kan du manuellt redigera den nya projektfilen för att stödja kompilering på både den gamla och den nya kompilatorn. I följande exempel visas hur du kompilerar för både Visual Studio 2015 och Visual Studio 2017:

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

LNK2019: Olöst extern

För olösta symboler kan du behöva åtgärda dina projektinställningar.

  • Om källfilen finns på en plats som inte är standard, lade du till sökvägen till projektets inkluderingskataloger?

  • Om det externa objektet definieras i en .lib fil, har du angett sökvägen för lib i projektegenskaperna och är rätt version av .lib filen där?

  • Försöker du länka till en .lib fil som kompilerats med en annan version av Visual Studio? I så fall kan du läsa föregående avsnitt om beroenden för biblioteks- och byggverktyg.

  • Matchar argumenttyperna på anropsplatsen faktiskt en befintlig överbelastning av funktionen? Kontrollera att de underliggande typerna är vad du förväntar dig, både för alla typedefs i funktionens signatur och i koden som anropar funktionen.

Om du vill felsöka ouppklarade symbolfel kan du använda dumpbin.exe för att undersöka de symboler som definierats i en binär fil. Prova följande kommandorad för att visa symboler som definierats i ett bibliotek:

dumpbin.exe /LINKERMEMBER somelibrary.lib

/Zc:wchar_t (wchar_t Är intern typ)

(I Microsoft Visual C++ 6.0 och tidigare wchar_t implementerades inte som en inbyggd typ. Den deklarerades som wchar.h en typedef för unsigned short.) C++-standarden kräver en wchar_t inbyggd typ. Användning av typedef-versionen kan orsaka portabilitetsproblem. Om du uppgraderar från tidigare versioner av Visual Studio och ser kompilatorfelet C2664 eftersom koden försöker implicit konvertera en wchar_t till unsigned shortrekommenderar vi att du ändrar koden för att åtgärda felet i stället för att ange /Zc:wchar_t-. För mer information, se /Zc:wchar_t (wchar_t är ursprunglig typ).

Uppgradera med länkalternativen /NODEFAULTLIB, /ENTRYoch /NOENTRY

Länkalternativet /NODEFAULTLIB (eller egenskapen Ignorera alla standardbibliotekslänkar ) uppmanar länkaren att inte automatiskt länka i standardbiblioteken, till exempel CRT. Det innebär att varje bibliotek måste anges som indata individuellt. Den här listan över bibliotek finns i egenskapen Ytterligare beroenden i avsnittet Linker i dialogrutan Projektegenskaper .

Projekt som använder det här alternativet utgör ett problem när du uppgraderar, eftersom innehållet i vissa standardbibliotek omstrukturerades. Eftersom varje bibliotek måste anges i egenskapen Ytterligare beroenden eller på länkarkommandoraden måste du uppdatera listan med bibliotek så att alla aktuella namn används.

I följande tabell visas de bibliotek vars innehåll ändrades från och med Visual Studio 2015. Om du vill uppgradera måste du lägga till de nya biblioteksnamnen i den andra kolumnen till biblioteken i den första kolumnen. Vissa av dessa bibliotek är importbibliotek, men det bör inte spela någon roll.

Om du använde: Du måste använda följande bibliotek:
libcmt.lib libcmt.lib, , libucrt.liblibvcruntime.lib
libcmtd.lib libcmtd.lib, , libucrtd.liblibvcruntimed.lib
msvcrt.lib msvcrt.lib, , ucrt.libvcruntime.lib
msvcrtd.lib msvcrtd.lib, , ucrtd.libvcruntimed.lib

Samma problem gäller även om du använder /ENTRY alternativet eller /NOENTRY alternativet, som också har effekten att kringgå standardbiblioteken.

Fel som orsakas av förbättrad språkanpassning

Microsoft C++-kompilatorn har kontinuerligt förbättrat sin överensstämmelse med C++-standarden genom åren. Kod som kompilerats i tidigare versioner kan misslyckas med att kompilera i senare versioner av Visual Studio. Det beror på att kompilatorn flaggar ett fel som den tidigare ignorerade eller uttryckligen tillät.

Till exempel introducerades växeln /Zc:forScope tidigt i MSVC-historiken. Det tillåter icke-överensstämmande beteende för loopvariabler. Växeln är nu inaktuell och kan tas bort i framtida versioner. Vi rekommenderar starkt att du inte använder växeln när du uppgraderar koden. För mer information, se /Zc:forScope- är föråldrad.

Ett exempel på ett vanligt kompilatorfel som du kan se när du uppgraderar är när ett icke-const-argument skickas till en const-parameter. Äldre versioner av kompilatorn flaggade det inte alltid som ett fel. Mer information finns i Kompilatorns strängare konverteringar.

Mer information om specifika anpassningsförbättringar finns i Visual C++ ändringshistorik 2003–2015 och förbättringar av C++-överensstämmelse i Visual Studio.

Fel som rör <stdint.h> integraltyper

Rubriken <stdint.h> definierar typedefs och makron som, till skillnad från inbyggda integraltyper, garanterat har en angiven längd på alla plattformar. Några exempel är uint32_t och int64_t. Rubriken <stdint.h> lades till i Visual Studio 2010. Kod som skrevs före 2010 kan ha angett privata definitioner för dessa typer. Och dessa definitioner kanske inte alltid är konsekventa med definitionerna <stdint.h> .

Om felet är C2371 och en stdint typ är inblandad innebär det förmodligen att typen definieras i en rubrik antingen i koden eller i en biblioteksfil från tredje part. När du uppgraderar bör du eliminera alla anpassade definitioner av <stdint.h> typer, men jämför först de anpassade definitionerna med de aktuella standarddefinitionerna för att säkerställa att du inte introducerar nya problem.

Du kan trycka på F12 (Gå till definition) för att se var typen i fråga definieras.

Kompilatoralternativet /showIncludes kan vara användbart här. I dialogrutan Egenskapssidor för projektet väljer du sidan Konfigurationsegenskaper>C/C++>Avancerat och anger Visa inkluderar till Ja. Återskapa sedan projektet. Du ser listan över #include filer i utdatafönstret. Varje rubrik är indraget under rubriken som innehåller det.

Fel som rör CRT-funktioner

Många förändringar har gjorts i C-runtime genom åren. Många säkra versioner av funktioner har lagts till och vissa har tagits bort. Som vi beskrev tidigare i den här artikeln omstrukturerades dessutom Microsofts implementering av CRT i Visual Studio 2015 till nya binärfiler och associerade .lib filer.

Om ett fel involverar en CRT-funktion söker du i Visual C++ ändringshistorik 2003–2015 eller förbättringar av C++-överensstämmelsen i Visual Studio för att se om artiklarna innehåller ytterligare information. Om felet är LNK2019 kontrollerar du att funktionen inte har tagits bort. Om du är säker på att funktionen fortfarande finns och den anropande koden är korrekt kontrollerar du om projektet använder /NODEFAULTLIB. I så fall måste du uppdatera biblioteklistan för att använda de nya universella (UCRT) biblioteken. Mer information finns i avsnittet ovan om Bibliotek och beroenden.

Om felet gäller printf eller scanfkontrollerar du att du inte privat definierar någon av funktionerna utan att inkludera stdio.h. I så fall kan du antingen ta bort de privata definitionerna eller länka till legacy_stdio_definitions.lib. Du kan ange det här biblioteket i dialogrutan Egenskapssidor under Konfigurationsegenskaper>Länkar>Indata, i egenskapen Ytterligare beroenden. Om du länkar till Windows SDK 8.1 eller tidigare lägger du till legacy_stdio_definitions.lib.

Om felet omfattar formatsträngsargument beror det förmodligen på att kompilatorn är striktare när det gäller att framtvinga standarden. Mer information finns i ändringshistoriken. Var uppmärksam på eventuella fel här, eftersom de kan utgöra en säkerhetsrisk.

Fel som orsakas av ändringar i C++-standarden

Själva C++-standarden har utvecklats på sätt som inte alltid är bakåtkompatibla. C++11 introducerade flyttsemantik, nya nyckelord och andra språk- och standardbiblioteksfunktioner. Dessa ändringar kan potentiellt orsaka kompilatorfel och till och med olika körningsbeteenden.

Ett gammalt C++-program kan till exempel innehålla iostream.h rubriken. Den här rubriken blev inaktuell tidigt i C++-historiken och togs så småningom bort helt från Visual Studio. I det här fallet måste du använda <iostream> och skriva om koden. Mer information finns i Uppdatera gammal iostream kod.

C4838: varning för begränsande konvertering

C++-standarden anger nu att konverteringar från osignerade till signerade integralvärden begränsar konverteringarna. Kompilatorn har inte genererat den här varningen före Visual Studio 2015. Kontrollera varje förekomst för att se till att begränsningen inte påverkar kodens korrekthet.

Varningar om att använda säkra CRT-funktioner

Under årens lopp har säkra versioner av C-körningsfunktioner introducerats. Även om de gamla, icke-säkra versionerna fortfarande är tillgängliga rekommenderar vi att du ändrar koden för att använda de säkra versionerna. Kompilatorn utfärdar en varning om användningen av de icke-säkra versionerna. Du kan välja att inaktivera eller ignorera dessa varningar. Om du vill inaktivera varningen för alla projekt i lösningen öppnar du Visa>egenskapshanterare, markerar alla projekt som du vill inaktivera varningen för, högerklickar på de markerade objekten och väljer Egenskaper. I dialogrutan Egenskapssidor under Konfigurationsegenskaper>C/C++>Avancerat väljer du Inaktivera specifika varningar. Välj listrutepilen och välj sedan Redigera. Ange 4996 i textrutan. (Inkludera inte prefixet C.) Mer information finns i Portning för att använda säker CRT.

Fel som orsakas av ändringar i Windows-API:er eller föråldrade SDK:er

Under årens lopp har Windows-API:er och datatyper lagts till och ibland ändrats eller tagits bort. Dessutom har andra SDK:er som inte tillhörde kärnoperativsystemet kommit och gått. Äldre program kan innehålla anrop till API:er som inte längre finns. De kan också innehålla anrop till API:er i andra Microsoft SDK:er som inte längre stöds. Du kan se felmeddelanden om saknade Windows-API:er eller om API:er från äldre Microsoft SDK:er. Det är möjligt att API:erna har tagits bort eller ersatts av nyare, säkrare funktioner.

Dokumentationen för Windows API listar de minsta och största operativsystem som stöds. Om du vill ha information om ett specifikt Windows-API letar du upp det i API-indexet för Windows-skrivbordsprogram.

Windows-version

När du uppgraderar ett program som använder Windows-API:et antingen direkt eller indirekt måste du bestämma vilken Windows-version som ska stödjas. I de flesta fall är Windows 7 ett bra val. Mer information finns i Problem med rubrikfil. Makrot WINVER definierar den äldsta versionen av Windows som programmet är utformat för att köras på. Om ditt MFC-program sätter versionen WINVER till 0x0501 (Windows XP) får du en varning eftersom MFC inte längre stöder XP, även om byggverktygen har ett XP-kompatibilitetsläge. Stöd för byggverktyg för Windows XP upphörde i Visual Studio 2017 och stödet för Windows 7, 8.0 och 8.1 upphörde i Visual Studio 2026.

Mer information finns i Uppdatera windows-målversionen och Fler inaktuella huvudfiler.

ATL/MFC

ATL och MFC är relativt stabila API:er, men ändringar görs ibland. Mer information finns i Visual C++ ändringshistorik 2003–2015, Nyheter för Visual C++ i Visual Studio och förbättringar av C++-överensstämmelse i Visual Studio.

LNK 2005 _DllMain@12 redan definierat i MSVCRTD.lib

Det här felet kan inträffa i MFC-program. Det anger ett beställningsproblem mellan CRT-biblioteket och MFC-biblioteket. MFC måste länkas först så att det tillhandahåller new och delete operatorer. Åtgärda felet genom att använda växeln /NODEFAULTLIB för att ignorera dessa standardbibliotek: MSVCRTD.lib och mfcs140d.lib. Lägg sedan till samma bibliotek som ytterligare beroenden.

32 vs 64 bitar

Om din ursprungliga kod kompileras för 32-bitarssystem kan du skapa en 64-bitarsversion i stället för (eller utöver) en ny 32-bitarsapp. I allmänhet bör du först kompilera programmet i 32-bitarsläge och sedan försöka med 64-bitars. Kompilering för 64-bitars är enkelt, men i vissa fall kan det avslöja buggar som har dolts av 32-bitarsversioner.

Du bör också vara medveten om möjliga kompileringstids- och körtidsproblem som är relaterade till pekarens storlek, tids- och storleksvärden samt storleksspecifika formatspecificerare i printf och scanf-funktioner. Mer information finns i Konfigurera Microsoft C++ för 64-bitars, x64-mål och Vanliga problem med Microsoft C++ 64-bitarsmigrering. Fler migreringstips finns i Programmeringsguide för 64-bitars Windows.

Unicode jämfört med MBCS/ASCII

Innan Unicode standardiserades använde många program MBCS (Multibyte Character Set) för att representera tecken som inte ingick i ASCII-teckenuppsättningen. I äldre MFC-projekt var MBCS standardinställningen. När du uppgraderar ett sådant program visas varningar som rekommenderar att du använder Unicode i stället. Om du bestämmer dig för att konverteringen till Unicode inte är värd utvecklingskostnaden kan du välja att inaktivera eller ignorera varningen. Om du vill inaktivera den för alla projekt i lösningen öppnar du Visa>egenskapshanterare, markerar alla projekt som du vill inaktivera varningen för, högerklickar på de markerade objekten och väljer Egenskaper. I dialogrutan Egenskapssidor väljer du Konfigurationsegenskaper>C/C++>Avancerat. I egenskapen Inaktivera specifika varningar öppnar du listrutepilen och väljer sedan Redigera. Ange 4996 i textrutan. (Inkludera inte prefixet C.) Välj OK för att spara egenskapen och välj sedan OK för att spara ändringarna.

Mer information finns i Portning från MBCS till Unicode. Allmän information om MBCS jämfört med Unicode finns i Text och strängar i Microsoft C++ och Internationalisering .

Se även

Uppgradera projekt från tidigare versioner av Microsoft C++
förbättringar av C++-överensstämmelse i Visual Studio