три реализации одного стандартаthree implementations of one standard

GCC vs Clang vs MSVC

Стандарт C++ определяет поведение программы, а не то, как компилятор устроен внутри — отсюда три полностью независимые реализации с разной архитектурой, разными диагностиками и, что важнее всего на практике, несовместимыми ABI. Подробный профиль каждого — с историей, устройством, санитайзерами, расширениями и инструментами — вынесен в отдельные статьи; здесь — сравнение, сводная таблица плюсов/минусов, практические различия и обзор ещё полутора десятков компиляторов и целей компиляции.The C++ standard defines a program's behavior, not how a compiler is built internally — hence three fully independent implementations with different architectures, different diagnostics, and, most importantly in practice, incompatible ABIs. A detailed profile of each — history, internals, sanitizers, extensions, and tooling — lives in its own article; here you'll find the comparison, a summary pros/cons table, practical differences, and an overview of another dozen-and-a-half compilers and compilation targets.

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

Три подробные статьиThree detailed articles

Три архитектуры — короткоThree architectures — in brief

GCCClangMSVC
IRIRGIMPLE / RTLLLVM IRзакрытый, недокументированныйclosed, undocumented
модельdesignмонолит, компилятор+бэкенд слитноmonolithic, compiler+backend fusedпереиспользуемые библиотеки (libclang, LLVM backend)reusable libraries (libclang, the LLVM backend)часть Visual Studio / MSBuildpart of Visual Studio / MSBuild
лицензияlicenseGPLApache 2.0 (с исключениями LLVM)(with LLVM exceptions)проприетарнаяproprietary
платформаplatformLinux (основная)(primary), вездеeverywhereвезде, основной на macOS/iOSeverywhere, primary on macOS/iOSWindows (только)(only)
расширяемостьextensibilityGCC plugins (нестабильный API)(unstable API)LibTooling/libclang (стабильный API)(stable API)нет прямого аналогаno direct equivalent

Другие компиляторы и цели компиляцииOther compilers & compilation targets

За пределами трёх основных — большой хвост компиляторов и таргетов: часть из них просто пересборка GCC под конкретную архитектуру (короткий абзац каждому), часть — самостоятельные, архитектурно непохожие проекты.Beyond the three major ones there's a long tail of compilers and targets: some are simply GCC rebuilt for a specific architecture (a short paragraph each), others are independent projects with genuinely different architectures.

01

MinGW / MinGW-w64

Не отдельный компилятор — это GCC, собранный под таргет Windows, плюс набор заголовков и import-библиотек для Windows API вместо glibc. Даёт нативные .exe/.dll без зависимости от POSIX-слоя (в отличие от Cygwin), но использует Itanium-подобный ABI GCC — отсюда та самая несовместимость с MSVC ABI. MinGW-w64 — форк оригинального MinGW с поддержкой 64-бит и заметно более широким покрытием Windows API.Not a separate compiler — it's GCC built for the Windows target, plus a set of headers and import libraries for the Windows API instead of glibc. It produces native .exe/.dll files with no dependency on a POSIX layer (unlike Cygwin), but uses GCC's Itanium-like ABI — hence that same incompatibility with the MSVC ABI. MinGW-w64 is a fork of the original MinGW with 64-bit support and noticeably broader Windows API coverage.

02

AVR-GCC

GCC, нацеленный на 8-битные микроконтроллеры Atmel/Microchip AVR (та же архитектура, что в классическом Arduino) — стандартный компилятор тулчейна Arduino IDE под капотом. Работает в условиях единиц килобайт flash/RAM, поэтому STL и исключения C++ на AVR либо недоступны, либо требуют урезанных реализаций (avr-libstdc++).GCC targeting Atmel/Microchip's 8-bit AVR microcontrollers (the same architecture used in classic Arduino boards) — the standard compiler under the hood of the Arduino IDE toolchain. It operates under constraints of just a few kilobytes of flash/RAM, so the STL and C++ exceptions on AVR are either unavailable or require stripped-down implementations (avr-libstdc++).

03

m68k-GCC (Motorola 68000Motorola 68000)

GCC-таргет для семейства процессоров Motorola 68k — архитектуры, стоявшей в классических Mac, Amiga, Sega Genesis/Mega Drive и до сих пор используемой в части встраиваемых и авиационных систем. Практическая значимость сегодня — ретро-разработка (гомбрю для Sega Genesis) и поддержка легаси-оборудования промышленного назначения, которое физически не заменено.A GCC target for the Motorola 68k processor family — the architecture that powered classic Macs, the Amiga, the Sega Genesis/Mega Drive, and is still used in some embedded and avionics systems today. Its practical relevance now is retro development (Sega Genesis homebrew) and support for legacy industrial hardware that hasn't been physically replaced.

04

LoongArch64

Собственный набор инструкций китайской компании Loongson (2021), архитектурно независимый от MIPS (на котором были основаны более ранние процессоры Loongson) — создан из соображений технологического суверенитета. Поддержка добавлена в GCC и Clang/LLVM за последние несколько лет; используется в основном во внутренних китайских проектах импортозамещения десктопов и серверов.A proprietary instruction set from the Chinese company Loongson (2021), architecturally independent of MIPS (which earlier Loongson processors were based on) — created for reasons of technological sovereignty. Support was added to GCC and Clang/LLVM over the past several years; it's used mainly in internal Chinese desktop/server import-substitution projects.

05

MIPS / MIPSel

Классическая RISC-архитектура (1981, MIPS Computer Systems), исторически значимая для сетевого оборудования (роутеры), игровых консолей (PlayStation, Nintendo 64) и учебных курсов компьютерной архитектуры за счёт простого, ортогонального набора команд. MIPSel — little-endian вариант той же архитектуры (обычный MIPS исторически big-endian) — оба таргета давно и стабильно поддерживаются GCC.A classic RISC architecture (1981, MIPS Computer Systems), historically significant for networking hardware (routers), game consoles (PlayStation, Nintendo 64), and computer-architecture courses thanks to its simple, orthogonal instruction set. MIPSel is the little-endian variant of the same architecture (plain MIPS was historically big-endian) — both targets have long been stably supported by GCC.

06

NVC++ (NVIDIA HPC SDK)

Не вариант GCC — независимый компилятор NVIDIA (бывший PGI C++, приобретённый в 2013), нацеленный на HPC-нагрузки с гетерогенным исполнением на CPU+GPU из одного исходника C++ через стандартную парадигму std::execution/parallel algorithms без CUDA-специфичного синтаксиса. Ключевая особенность — GPU-код генерируется прямо из обычных std::for_each/std::transform с policy std::execution::par, а не через отдельный язык расширений (в отличие от CUDA C++ у nvcc).Not a GCC variant — an independent NVIDIA compiler (formerly PGI C++, acquired in 2013), targeting HPC workloads with heterogeneous CPU+GPU execution from a single C++ source via the standard std::execution/parallel-algorithms paradigm, with no CUDA-specific syntax. The key feature: GPU code is generated straight from ordinary std::for_each/std::transform with the std::execution::par policy, rather than through a separate extension language (unlike CUDA C++ under nvcc).

07

PowerPC (POWER)

RISC-архитектура альянса Apple-IBM-Motorola (1991), стоявшая в Mac до перехода на Intel (2006) и в игровых консолях (Xbox 360, PS3, Wii) — сегодня основная ниша это высокопроизводительные серверы IBM POWER (важно для highly-available enterprise-систем) и часть встраиваемых/авиационных применений. Поддерживается и GCC, и Clang/LLVM как полноценный первоклассный таргет.A RISC architecture from the Apple-IBM-Motorola alliance (1991), which powered the Mac before the switch to Intel (2006) and game consoles (Xbox 360, PS3, Wii) — today its main niche is high-performance IBM POWER servers (important for highly-available enterprise systems) and some embedded/avionics applications. Supported by both GCC and Clang/LLVM as a full first-class target.

08

RISC-V

Открытый, свободный от лицензионных отчислений набор инструкций (UC Berkeley, 2010) — в отличие от ARM, любая компания может реализовать RISC-V железо без выплат за лицензию на архитектуру. Быстрее всех новых архитектур получил зрелую поддержку в GCC и LLVM именно благодаря открытости — сегодня растущая ниша во встраиваемых системах и всё активнее в серверных чипах как альтернатива x86/ARM.An open, royalty-free instruction set (UC Berkeley, 2010) — unlike ARM, any company can implement RISC-V hardware without paying architecture licensing fees. Of all the newer architectures, it gained mature GCC and LLVM support the fastest, precisely because of its openness — today it's a growing niche in embedded systems and increasingly in server chips as an x86/ARM alternative.

09

SPARC

RISC-архитектура Sun Microsystems (1985), исторически ядро серверов Sun/Oracle под Solaris — сегодня заметно нишевая, но всё ещё поддерживается Oracle в новых поколениях серверов (SPARC M8) для существующих enterprise-заказчиков с многолетними инвестициями в платформу. GCC поддерживает SPARC как таргет с 1990-х.Sun Microsystems's RISC architecture (1985), historically the core of Sun/Oracle servers running Solaris — noticeably niche today, but still maintained by Oracle in newer server generations (SPARC M8) for existing enterprise customers with decades of platform investment. GCC has supported SPARC as a target since the 1990s.

10

TI (Texas Instruments) компиляторыcompilers

Собственная (не GCC-based) линейка компиляторов Texas Instruments для своих DSP и микроконтроллеров (Code Composer Studio для MSP430, C2000, Sitara) — специализированные оптимизации под конкретную DSP-архитектуру (например, эффективное использование множественных аппаратных умножителей), которые универсальный GCC/LLVM backend не всегда покрывает так же плотно. Ниша — цифровая обработка сигналов, промышленный контроль, автомобильная электроника.Texas Instruments's own (not GCC-based) compiler lineup for its DSPs and microcontrollers (Code Composer Studio for the MSP430, C2000, Sitara families) — specialized optimizations for a specific DSP architecture (for example, efficient use of multiple hardware multipliers) that a general-purpose GCC/LLVM backend doesn't always cover as tightly. The niche: digital signal processing, industrial control, automotive electronics.

11

VAX

CISC-архитектура DEC (1977), в своё время эталонная платформа для Unix-исследований (4BSD разрабатывался именно на VAX) — сегодня чисто историческая ценность и ретро-компьютинг/эмуляция (SIMH). GCC какое-то время поддерживал VAX как таргет, но это один из наименее активно поддерживаемых бэкендов — иллюстрация того, что даже у GCC список таргетов не бессмертен: неактивные бэкенды со временем выпадают из дерева исходников.DEC's CISC architecture (1977), once the reference platform for Unix research (4BSD was developed on VAX) — today purely of historical value and retro-computing/emulation (SIMH) interest. GCC supported VAX as a target for a while, but it's one of the least actively maintained backends — an illustration that even GCC's target list isn't immortal: inactive backends eventually drop out of the source tree.

12

Zig cc

Не отдельный, независимо написанный компилятор C++ — Zig распространяется в комплекте с Clang и полным набором заголовков/раннтаймов libc для десятков платформ, и команда zig c++ фактически является обёрткой над Clang с автоматически подставленными флагами кросс-компиляции. Причина упоминания в контексте GCC/Clang/MSVC — это на практике самый простой способ кросс-компилировать C/C++ под произвольную комбинацию ОС+архитектуры одной командой, без ручной сборки toolchain.Not a separately, independently written C++ compiler — Zig ships bundled with Clang and a full set of libc headers/runtimes for dozens of platforms, and the zig c++ command is effectively a wrapper around Clang with cross-compilation flags filled in automatically. It's worth mentioning alongside GCC/Clang/MSVC because in practice it's the easiest way to cross-compile C/C++ for an arbitrary OS+architecture combination with a single command, with no manual toolchain assembly.

13

ELCC / прочие узкоспециализированные таргетыother narrow-niche targets

ELCC (e.g. embedded/legacy toolchains для конкретных производителей контроллеров) — пример класса компиляторов, которые почти всегда представляют собой пересборку GCC под очень узкий вендор-специфичный таргет с минимальными патчами (свои дефолтные флаги, свои стандартные библиотеки под конкретный чип). Общий паттерн для всей этой длинной хвостовой части экосистемы: если производитель железа не написал компилятор с нуля (как TI или NVIDIA), в 95% случаев это GCC с патчами.ELCC (e.g. embedded/legacy toolchains for specific controller vendors) is an example of a whole class of compilers that are almost always GCC rebuilt for a very narrow, vendor-specific target with minimal patches (their own default flags, their own standard libraries for a specific chip). The general pattern across this whole long tail of the ecosystem: if a hardware vendor didn't write a compiler from scratch (like TI or NVIDIA), 95% of the time it's GCC with patches.

Практические различияPractical differences

01

Качество диагностики — исторически сильная сторона ClangDiagnostic quality — historically Clang's strong suit

Clang изначально спроектирован с прицелом на IDE-интеграцию и точные, дружелюбные сообщения об ошибках (с подчёркиванием конкретного проблемного фрагмента, предложением исправления). Ошибки шаблонных инстанциаций в Clang печатаются компактнее, чем в GCC — хотя GCC за последние версии заметно сократил разрыв.Clang was designed from the start with IDE integration in mind, along with precise, friendly error messages (underlining the specific problematic fragment, suggesting a fix). Template-instantiation errors print more compactly in Clang than in GCC — though GCC has meaningfully closed that gap in recent versions.

02

Несовместимость ABI между GCC/Clang (на Linux, общий Itanium ABI) и MSVCThe ABI incompatibility between GCC/Clang (on Linux, sharing the Itanium ABI) and MSVC

GCC и Clang на Linux следуют общему стандарту Itanium C++ ABI — объектные файлы, собранные разными компиляторами по этому стандарту, обычно линкуются друг с другом. MSVC использует собственный, несовместимый ABI: mangling имён, layout виртуальных таблиц и передача параметров устроены иначе — библиотеку, собранную MSVC, нельзя напрямую слинковать с кодом, собранным MinGW (GCC под Windows), и наоборот.GCC and Clang on Linux follow the shared Itanium C++ ABI standard — object files built by different compilers under that standard generally link together fine. MSVC uses its own, incompatible ABI: name mangling, vtable layout, and parameter passing all work differently — a library built with MSVC cannot be directly linked against code built with MinGW (GCC on Windows), or vice versa.

// один и тот же символ, разный mangled-вид у разных компиляторов:// the same symbol, mangled differently by different compilers:
int add(int a, int b);

// Itanium ABI (GCC/Clang):  _Z3addii// Itanium ABI (GCC/Clang):  _Z3addii
// MSVC:                     ?add@@YAHHH@Z// MSVC:                     ?add@@YAHHH@Z
03

Скорость сборки и предпочитаемая модель параллелизмаBuild speed and the preferred parallelism model

Clang исторически быстрее в парсинге за счёт более простого, изначально спроектированного под инкрементальную работу фронтенда; GCC часто выигрывает в качестве генерируемого кода на некоторых бенчмарках за счёт более зрелого набора backend-оптимизаций, накопленных за десятилетия. Разница ощутима на больших C++-проектах, но нестабильна — сильно зависит от версии обоих компиляторов и конкретного кода.Clang has historically been faster at parsing thanks to a simpler frontend designed from the start for incremental work; GCC often wins on generated-code quality in certain benchmarks thanks to a more mature set of backend optimizations accumulated over decades. The difference is noticeable on large C++ projects but isn't stable — it depends heavily on both compilers' versions and the specific code.

04

Поддержка стандарта — расхождение по фичам C++20/23Standard support — divergence on C++20/23 features

Ни один из трёх компиляторов не реализует новый стандарт целиком одновременно с публикацией — модули C++20, например, долго были рабочими на разном уровне зрелости у всех трёх, с разной поддержкой сборочными системами (CMake). Практическое следствие: перед использованием свежей фичи стандарта нужно сверяться с таблицами поддержки конкретных версий компиляторов, а не только с номером стандарта.None of the three compilers implements a new standard in full at the moment it's published — C++20 modules, for instance, spent a long time working at differing levels of maturity across all three, with uneven build-system (CMake) support. The practical consequence: before using a freshly standardized feature, check the support tables for specific compiler versions, not just the standard's number.

ГраблиGotchas

Undefined Behavior компилируется по-разному у всех трёх — и это не багUndefined behavior compiles differently across all three — and that's not a bug

Стандарт намеренно не определяет поведение UB-кода (разыменование нулевого указателя, signed integer overflow), поэтому GCC, Clang и MSVC свободны генерировать для него любой код — включая код, который «магически» удаляет проверку или ведёт себя иначе на разных уровнях оптимизации. Код, «работавший» на одном компиляторе, может сломаться просто при смене на другой, если в нём было скрытое UB.The standard deliberately leaves UB code (dereferencing a null pointer, signed integer overflow) undefined, so GCC, Clang, and MSVC are all free to generate whatever code they like for it — including code that "magically" removes a check or behaves differently at different optimization levels. Code that "worked" on one compiler can break simply by switching to another if it contained hidden UB.

Флаги оптимизации не переносятся между компиляторами один в одинOptimization flags don't map one-to-one between compilers

GCC и Clang в основном совместимы по флагам (-O2, -march=native понимают оба), но многие тонкие флаги специфичны или ведут себя по-разному. MSVC использует полностью другой синтаксис флагов (/O2 вместо -O2) — сборочный скрипт, написанный под один компилятор, почти никогда не переносится дословно на другой.GCC and Clang are largely compatible on flags (both understand -O2, -march=native), but many finer-grained flags are compiler-specific or behave differently. MSVC uses an entirely different flag syntax (/O2 instead of -O2) — a build script written for one compiler almost never carries over verbatim to another.

clang-cl — не «Clang, но с флагами MSVC», это два разных драйвераclang-cl isn't "Clang with MSVC flags" — they're two different drivers

clang-cl — драйвер Clang, принимающий синтаксис флагов MSVC и по умолчанию нацеленный на ABI-совместимость с MSVC на Windows, но использующий фронтенд и оптимизации именно Clang/LLVM. Это отдельный, третий режим работы — не то же самое, что обычный clang++ с флагами GCC-style.clang-cl is a Clang driver that accepts MSVC-style flags and, by default, targets ABI compatibility with MSVC on Windows, while still using Clang/LLVM's own frontend and optimizations. It's a distinct, third mode of operation — not the same thing as regular clang++ with GCC-style flags.