Skip to content
C++
Compiler
Updated 2026-05-01T00:00:00.000Z

MSVC

Microsoft Visual C++ — Windows-native compiler required for COM, WinRT, UWP, and Xbox development. Ships with Visual Studio and Build Tools.

TL;DR

MSVC is the Windows-native C++ compiler. Required for COM, WinRT, UWP, and Xbox development. Use /W4 /WX for warnings, /O2 for release optimization, and /std:c++20 or /std:c++latest for modern C++. Available free via Visual Studio Community or standalone Build Tools.

bat
REM Command line (Developer Command Prompt)
cl /std:c++20 /O2 /W4 /EHsc /Fe:myapp.exe main.cpp

REM With sanitizers (VS 2019 16.9+)
cl /std:c++20 /O1 /fsanitize=address /Zi /Fe:myapp.exe main.cpp

Standards support

StandardFlag
C++14/std:c++14
C++17/std:c++17
C++20/std:c++20
C++23 (partial)/std:c++latest

Use /std:c++20 for production; /std:c++latest to track C++23/26 features in development.

Essential flags

Warning flags

bat
/W0    REM No warnings
/W1    REM Severe warnings only
/W2    REM Significant warnings (default)
/W3    REM Production quality warnings
/W4    REM Informational warnings (recommended)
/Wall  REM All warnings including rarely-used ones (noisy)
/WX    REM Treat warnings as errors

Recommended: /W4 /WX for new projects.

Optimization flags

bat
/Od    REM No optimization (debug)
/O1    REM Minimize size
/O2    REM Maximize speed (release default)
/Ox    REM Full optimization
/GL    REM Whole-program optimization (link-time)
/LTCG  REM Link-time code generation (pair with /GL)

Exception handling

bat
/EHsc  REM Standard C++ exception handling (use this)
/EHa   REM Also catches SEH (structured exceptions)
/EHs   REM No async exceptions

Always specify /EHsc explicitly. Without it, destructors may not run during stack unwinding.

Debug information

bat
/Zi    REM PDB debug info (separate .pdb file)
/ZI    REM PDB with Edit-and-Continue support (dev only)
/Zd    REM Line numbers only

Runtime library

bat
/MD    REM Dynamic CRT (release) — use in DLLs and shared libraries
/MDd   REM Dynamic CRT (debug)
/MT    REM Static CRT (release) — for standalone executables
/MTd   REM Static CRT (debug)

All components in a project must use the same runtime. Mixing /MD and /MT causes linker errors or runtime crashes.

Sanitizers (VS 2019+)

bat
REM AddressSanitizer
cl /fsanitize=address /Zi /Od main.cpp

REM In CMake
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address")

MSVC ASan requires VS 2019 16.9+ and works on x64 only.

CMake integration

cmake
cmake_minimum_required(VERSION 3.20)
project(myapp CXX)
set(CMAKE_CXX_STANDARD 20)

add_executable(myapp main.cpp)

target_compile_options(myapp PRIVATE
  $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX /EHsc>
)

# Enable WPO/LTCG for Release
set_target_properties(myapp PROPERTIES
  INTERPROCEDURAL_OPTIMIZATION_RELEASE ON
)

Clang-cl — Clang with MSVC ABI

clang-cl is a drop-in replacement that accepts MSVC flags but uses Clang's frontend:

bat
clang-cl /std:c++20 /O2 /W4 /EHsc /Fe:myapp.exe main.cpp

Use clang-cl when you want:

  • Clang's better error messages on Windows
  • clang-tidy integration with MSVC ABI compatibility
  • The same binary ABI as MSVC (COM, WinRT compatible)

Precompiled headers

cpp
// stdafx.h (or pch.h)
#pragma once
#include <vector>
#include <string>
#include <memory>
// ... all stable headers
bat
REM Create PCH
cl /Yc"pch.h" /FpMyPCH.pch pch.cpp

REM Use PCH
cl /Yu"pch.h" /FpMyPCH.pch main.cpp

In CMake:

cmake
target_precompile_headers(myapp PRIVATE pch.h)

Common MSVC-specific extensions

cpp
// __declspec — Windows-specific attributes
__declspec(dllexport) void myFunc();  // Export from DLL
__declspec(dllimport) void myFunc();  // Import from DLL
__declspec(noinline) void slow();     // Prevent inlining
__declspec(align(16)) float data[4]; // Alignment

// Structured Exception Handling (Windows SEH)
__try {
    // code that might throw SEH
} __except(EXCEPTION_EXECUTE_HANDLER) {
    // handle
}

// Prefer standard [[nodiscard]], [[likely]] etc. over MSVC extensions

Notable MSVC quirks

/permissive- — enables strict conformance mode. Add this to catch non-portable code:

bat
cl /std:c++20 /permissive- main.cpp

Two-phase lookup: MSVC historically had broken two-phase name lookup. /permissive- fixes this. Always use it in new projects.

__int64 vs long long: On MSVC, long is 32-bit even on 64-bit Windows (LLP64 model). Use int64_t / uint64_t from <cstdint> for portable 64-bit integers.

min/max macros: Windows headers define min/max as macros. Use #define NOMINMAX before including <windows.h> or use (std::min)() with parentheses.

cpp
#define NOMINMAX
#include <windows.h>
#include <algorithm>

auto x = std::min(a, b);  // Fine
Edit on GitHubUpdated 2026-05-01T00:00:00.000Z