закрытая архитектура, плотная интеграция с Windowsa closed architecture, tight Windows integration

MSVC — Microsoft Visual C++

Компилятор Microsoft, развиваемый как часть Visual Studio с начала 1990-х — единственный из трёх с полностью закрытой внутренней архитектурой, зато с лучшей в индустрии интеграцией с Windows-специфичными технологиями и первоклассным интегрированным отладчиком.Microsoft's compiler, developed as part of Visual Studio since the early 1990s — the only one of the three with a fully closed internal architecture, but with the best-in-industry integration with Windows-specific technology and a first-class integrated debugger.

частый вопрос на собеседованииcommon interview question

ИсторияHistory

Развивается Microsoft с начала 1990-х, вырос из более раннего Microsoft C/C++ Compiler (частью которого был знаменитый QuickC). Visual C++ 1.0 вышел в 1993 году как часть первой версии Visual Studio-подобной среды. В отличие от GCC/Clang, версионирование MSVC исторически привязано не к номерам самого компилятора (_MSC_VER), а к версии Visual Studio (VS2015, VS2017, VS2019, VS2022) — что долго затрудняло сравнение поддержки фич стандарта между тремя компиляторами по одной шкале, так как одна и та же major-версия Visual Studio получает обновления компилятора внутри минорных релизов (16.0 → 16.11 в рамках VS2019).Developed by Microsoft since the early 1990s, grown out of the earlier Microsoft C/C++ Compiler (which the famous QuickC was part of). Visual C++ 1.0 shipped in 1993 as part of the first Visual Studio-like environment. Unlike GCC/Clang, MSVC's versioning has historically been tied not to the compiler's own numbers (_MSC_VER) but to the Visual Studio release (VS2015, VS2017, VS2019, VS2022) — which long made it awkward to compare standard-feature support across all three compilers on one scale, since the same major Visual Studio version gets compiler updates within minor releases (16.0 → 16.11 within VS2019).

Значимый поворот последних лет — переписанный с нуля фронтенд-парсер (2019+) ради полной поддержки C++20 modules и лучшего соответствия стандарту в целом, а также появление опции /std:c++latest для отслеживания черновика ещё не финализированного стандарта — сигнал, что Microsoft заметно ускорила темп синхронизации с ISO C++ по сравнению с 2010-ми, когда MSVC заметно отставал по поддержке C++11.A significant recent shift is a from-scratch rewrite of the frontend parser (2019+) for full C++20 modules support and better overall standard conformance, along with the /std:c++latest option for tracking a not-yet-finalized draft standard — a signal that Microsoft has noticeably accelerated its pace of syncing with ISO C++ compared to the 2010s, when MSVC lagged noticeably on C++11 support.

Запуск изнутри: cl.exe → c1xx/c2 → link.exeWhat happens under the hood: cl.exe → c1xx/c2 → link.exe

Архитектурно похоже на GCC/Clang (driver + внутренние компоненты), но большая часть внутренних инструментов не документирована публично и не предназначена для прямого запуска пользователем.Architecturally similar to GCC/Clang (a driver plus internal components), but most of the internal tools aren't publicly documented and aren't meant to be run directly by the user.

01

cl.exe — driver

Аналог g++/clang++ — разбирает флаги командной строки (в собственном синтаксисе, /O2 вместо -O2) и координирует внутренние компоненты. В отличие от GCC/Clang, флаг для «показать реальные команды без выполнения» не является публично документированной, стабильной частью интерфейса — на практике для этого чаще используют /showIncludes для зависимостей заголовков или сборку с verbosity через MSBuild.The analogue of g++/clang++ — parses command-line flags (in its own syntax, /O2 instead of -O2) and coordinates the internal components. Unlike GCC/Clang, a "show the real commands without running them" flag isn't a publicly documented, stable part of the interface — in practice, /showIncludes for header dependencies or a verbose MSBuild run are used instead.

02

c1xx / c1 — фронтендfrontend

Внутренний, недокументированный компонент, выполняющий препроцессор/парсинг/семантический анализ C++ (c1xx.dll) — аналог связки GCC-препроцессора и cc1plus, но без публичного описания промежуточных структур данных.An internal, undocumented component that performs C++ preprocessing/parsing/semantic analysis (c1xx.dll) — the analogue of GCC's preprocessor-plus-cc1plus combo, but with no public description of its intermediate data structures.

03

c2 — бэкенд, оптимизации и кодогенерацияbackend, optimization, and codegen

c2.dll получает промежуточное представление от c1xx (закрытый, недокументированный формат — в противовес открытым GIMPLE/LLVM IR) и выполняет оптимизации плюс генерацию машинного кода. Именно закрытость этого формата — ключевая причина, почему сторонние академические и коммерческие проекты не могут встроить собственный анализ на этом уровне, в отличие от LLVM IR у Clang.c2.dll receives an intermediate representation from c1xx (a closed, undocumented format — as opposed to the open GIMPLE/LLVM IR) and performs optimization plus machine-code generation. The closedness of this format is precisely why third-party academic and commercial projects cannot plug in their own analysis at this level, unlike with Clang's LLVM IR.

04

link.exe — линковкаlinking

Собственный линковщик Microsoft — генерирует PE-файл (см. жизненный цикл процесса) и PDB-файл отладочной информации. В отличие от GCC/Clang, где линковщик — отдельная от компилятора, взаимозаменяемая программа (ld/gold/lld), link.exe исторически теснее связан именно с MSVC-тулчейном.Microsoft's own linker — generates the PE file (see the process lifecycle) and the PDB debug-info file. Unlike GCC/Clang, where the linker is a separate, swappable program from the compiler (ld/gold/lld), link.exe is historically more tightly coupled to the MSVC toolchain specifically.

РасширяемостьExtensibility

У MSVC нет прямого аналога GCC plugins или Clang LibTooling — закрытая архитектура компилятора не предоставляет публичный API для подключения произвольного анализа к внутренним структурам данных компиляции. Расширяемость реализована на другом уровне — вокруг компилятора, а не внутри него.MSVC has no direct equivalent of GCC plugins or Clang LibTooling — the compiler's closed architecture doesn't expose a public API for hooking arbitrary analysis into internal compilation data structures. Extensibility is instead implemented at a different level — around the compiler, not inside it.

01

/analyze и настраиваемые наборы правилand configurable rule sets

Статический анализатор /analyze позволяет подключать собственные наборы правил (.ruleset файлы в Visual Studio) и писать собственные правила через отдельный, публично документированный API анализа (Static Analysis Extension API) — это не доступ к внутренностям компилятора, а изолированный слой поверх уже готовых диагностических данных.The /analyze static analyzer allows plugging in custom rule sets (.ruleset files in Visual Studio) and writing custom rules through a separate, publicly documented analysis API (the Static Analysis Extension API) — this isn't access to the compiler's internals, but an isolated layer on top of already-produced diagnostic data.

02

Visual Studio SDK и VSIX-расширенияand VSIX extensions

Расширения IDE (не компилятора) могут встраиваться в процесс сборки, добавлять собственные IntelliSense-провайдеры, но не могут менять поведение самого cl.exe на уровне компиляции — принципиальное архитектурное отличие от Clang, где IDE-уровень (clangd) и уровень компилятора построены на общем, открытом коде.IDE extensions (not compiler extensions) can hook into the build process and add their own IntelliSense providers, but cannot change cl.exe's own compilation-level behavior — a fundamental architectural difference from Clang, where the IDE layer (clangd) and the compiler layer are built on shared, open code.

03

clang-cl как обходной путьas a workaround

На практике, если проекту нужна расширяемость на уровне AST/IR при сохранении ABI-совместимости с MSVC-экосистемой, используют clang-cl — тогда доступны LibTooling/ASTMatchers Clang, а не внутренности самого MSVC.In practice, if a project needs AST/IR-level extensibility while staying ABI-compatible with the MSVC ecosystem, teams reach for clang-cl — that gives access to Clang's LibTooling/ASTMatchers, rather than MSVC's own internals.

СанитайзерыSanitizers

AddressSanitizer появился в MSVC значительно позже, чем в GCC/Clang (стабильно — с Visual Studio 2019 16.9, 2021 год), реализован как порт LLVM-версии ASan, но интегрированный с отладчиком Visual Studio (крашит с точным стеком и подсветкой строки прямо в IDE, без внешнего терминала).AddressSanitizer arrived in MSVC significantly later than in GCC/Clang (stable since Visual Studio 2019 16.9, in 2021), implemented as a port of LLVM's ASan, but integrated with the Visual Studio debugger (crashes with a precise stack trace and line highlighting right in the IDE, no external terminal needed).

// Visual Studio: /fsanitize=address
cl /fsanitize=address /Zi main.cpp

UBSan/TSan/MSan в MSVC нативно не реализованы вовсе. Практический обходной путь на Windows — clang-cl (Clang с MSVC-совместимым драйвером флагов и ABI, дающий доступ ко всему набору LLVM-санитайзеров) или WSL (Windows Subsystem for Linux) с настоящим Clang/GCC для полноценного Linux-окружения тестирования.UBSan/TSan/MSan aren't natively implemented in MSVC at all. The practical workaround on Windows is clang-cl (Clang with an MSVC-compatible flag driver and ABI, giving access to the full set of LLVM sanitizers) or WSL (Windows Subsystem for Linux) with real Clang/GCC for a full Linux testing environment.

Расширения и атрибутыExtensions and attributes

01

__declspec(dllexport) / __declspec(dllimport)

Явная маркировка символов, экспортируемых из DLL, обязательна на Windows — в отличие от Linux/ELF, где видимость символов по умолчанию либо глобальная (экспортируется всё), либо управляется через __attribute__((visibility("default"))) у GCC/Clang, но не требует парной аннотации на стороне импортирующего кода.Explicitly marking symbols exported from a DLL is mandatory on Windows — unlike on Linux/ELF, where symbol visibility is either global by default (everything is exported) or controlled via GCC/Clang's __attribute__((visibility("default"))), with no paired annotation required on the importing side.

// mylib.hpp — общий заголовок для сборки библиотеки и её использования — a shared header for both building the library and using it
#ifdef BUILDING_MYLIB
  #define MYLIB_API __declspec(dllexport)
#else
  #define MYLIB_API __declspec(dllimport)
#endif

MYLIB_API void doSomething();
02

SAL-аннотацииannotations (Source-code Annotation Language)

Разметка контрактов функций (_In_, _Out_, _In_reads_(n), _Success_(return != 0)) для статического анализатора /analyze — разработана Microsoft ещё в середине 2000-х, задолго до того, как C++ Core Guidelines предложили похожую идею через стандартизуемые атрибуты (gsl::not_null и подобные).Function-contract annotations (_In_, _Out_, _In_reads_(n), _Success_(return != 0)) for the /analyze static analyzer — designed by Microsoft back in the mid-2000s, well before the C++ Core Guidelines proposed a similar idea through standardizable attributes (gsl::not_null and the like).

void copyBuffer(_In_reads_(srcLen) const char* src, size_t srcLen,
                 _Out_writes_(dstLen) char* dst, size_t dstLen);
// /analyze проверит, что вызывающий код передаёт согласованные размеры буферов// /analyze checks that calling code passes consistent buffer sizes
03

#pragma директивы MSVCMSVC pragma directives

#pragma comment(lib, "user32.lib") (подключить библиотеку прямо из исходника, без правки настроек проекта/линковщика — уникальная для MSVC возможность), #pragma pack (аналог __attribute__((packed)), но директивой, действующей до следующего #pragma pack(), а не атрибутом на конкретной структуре).#pragma comment(lib, "user32.lib") (link a library directly from source, without touching project/linker settings — an MSVC-specific capability), #pragma pack (the analogue of __attribute__((packed)), but as a directive in effect until the next #pragma pack(), rather than an attribute on a specific struct).

Опции оптимизации подробноOptimization options in detail

Синтаксис флагов полностью отличается от GCC/Clang (/ вместо -) — сборочный скрипт, написанный под GCC/Clang, никогда не переносится дословно.The flag syntax is entirely different from GCC/Clang (/ instead of -) — a build script written for GCC/Clang never carries over verbatim.

флагflagчто делаетwhat it does
/Odбез оптимизаций — аналог -O0, лучшая отладкаno optimizations — the -O0 analogue, best debugging
/O1оптимизация под минимальный размер (аналог -Os у GCC/Clang, не -O1!)optimize for minimum size (the analogue of GCC/Clang's -Os, not -O1!)
/O2оптимизация под максимальную скорость — ближайший аналог -O2/-O3 у GCC/Clang, стандарт для продакшн-сборокoptimize for maximum speed — the closest analogue to GCC/Clang's -O2/-O3, the standard for production builds
/Ob2агрессивный inlining (управляется отдельно от общего уровня оптимизации, в отличие от GCC/Clang)aggressive inlining (controlled separately from the overall optimization level, unlike GCC/Clang)
/GL + /LTCGWhole Program Optimization — аналог -flto: /GL на этапе компиляции + /LTCG на этапе линковкиWhole Program Optimization — the -flto analogue: /GL at compile time plus /LTCG at link time
/fp:fastаналог -ffast-math — нарушающие строгое соответствие стандарту floating-point оптимизацииthe -ffast-math analogue — floating-point optimizations that break strict standard conformance
/arch:AVX2аналог -march — генерация кода под конкретный набор инструкцийthe -march analogue — generate code for a specific instruction set
/GS-отключить проверку стека на переполнение (buffer security check), включённую по умолчанию — обратное умолчание относительно GCC/Clang, где stack protector нужно включать явноdisable the stack buffer security check, which is on by default — the opposite default from GCC/Clang, where the stack protector must be enabled explicitly

Инструменты вокругTooling around it

01

Visual Studio IDE

Интегрированный отладчик (без внешних инструментов вроде gdb/lldb), профилировщик (CPU/GPU/память в одном окне), Memory Usage tool для снапшотов кучи между двумя точками выполнения — весь цикл разработки в одной среде без сборки отдельного тулчейна.An integrated debugger (no external tools like gdb/lldb needed), a profiler (CPU/GPU/memory in one window), a Memory Usage tool for heap snapshots between two points in execution — the entire development cycle in one environment with no separate toolchain to assemble.

02

Application Verifier

Инструмент уровня ОС (не компилятора) для перехвата типичных ошибок работы с кучей и хендлами Windows API в рантайме — дополняет ASan для проверок, специфичных именно для Windows-примитивов (handle leaks, некорректное использование критических секций).An OS-level (not compiler-level) tool for catching common heap and Windows API handle mistakes at runtime — complements ASan for checks specific to Windows primitives (handle leaks, incorrect critical-section usage).

03

vcpkg

Менеджер пакетов C++ от Microsoft, кроссплатформенный (работает и с GCC/Clang), но исторически ориентированный на удобство именно в связке с MSVC/Visual Studio — интеграция через MSBuild-property sheets «из коробки».Microsoft's C++ package manager, cross-platform (works with GCC/Clang too), but historically most convenient paired with MSVC/Visual Studio — out-of-the-box integration via MSBuild property sheets.

Плюсы и минусыPros and cons

плюсы:pros: лучшая интеграция с Windows-специфичными технологиями (COM, DirectX, Windows SDK), первоклассный интегрированный отладчик без внешних инструментов, SAL-аннотации ловят часть ошибок ещё на этапе статического анализа, заметно ускорившийся в последние годы темп синхронизации со стандартом.the best integration with Windows-specific technology (COM, DirectX, the Windows SDK), a first-class integrated debugger with no external tools needed, SAL annotations catch some errors at static-analysis time, a noticeably accelerated pace of standard conformance in recent years.

минусы:cons: только Windows, закрытая внутренняя архитектура исключает сторонние исследования/расширения компилятора на уровне AST/IR, только один нативный санитайзер (ASan), привязка версионирования к Visual Studio исторически путала сравнение возможностей между компиляторами.Windows-only, a closed internal architecture rules out third-party research or AST/IR-level extension of the compiler, only one native sanitizer (ASan), versioning tied to Visual Studio has historically muddled cross-compiler feature comparisons.