Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
c source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502 cc65 2.17
6502 cc65 2.18
6502 cc65 2.19
6502 cc65 trunk
ARM GCC 10.2.0 (linux)
ARM GCC 10.2.1 (none)
ARM GCC 10.3.0 (linux)
ARM GCC 10.3.1 (2021.07 none)
ARM GCC 10.3.1 (2021.10 none)
ARM GCC 10.5.0
ARM GCC 11.1.0 (linux)
ARM GCC 11.2.0 (linux)
ARM GCC 11.2.1 (none)
ARM GCC 11.3.0 (linux)
ARM GCC 11.4.0
ARM GCC 12.1.0 (linux)
ARM GCC 12.2.0 (linux)
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 12.5.0
ARM GCC 13.1.0 (linux)
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 13.4.0
ARM GCC 13.4.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 14.3.0
ARM GCC 14.3.0 (unknown-eabi)
ARM GCC 15.1.0
ARM GCC 15.1.0 (unknown-eabi)
ARM GCC 15.2.0
ARM GCC 15.2.0 (unknown-eabi)
ARM GCC 4.5.4 (linux)
ARM GCC 4.6.4 (linux)
ARM GCC 5.4 (linux)
ARM GCC 5.4.1 (none)
ARM GCC 6.3.0 (linux)
ARM GCC 6.4.0 (linux)
ARM GCC 7.2.1 (none)
ARM GCC 7.3.0 (linux)
ARM GCC 7.5.0 (linux)
ARM GCC 8.2.0 (WinCE)
ARM GCC 8.2.0 (linux)
ARM GCC 8.3.1 (none)
ARM GCC 8.5.0 (linux)
ARM GCC 9.2.1 (none)
ARM GCC 9.3.0 (linux)
ARM GCC trunk (linux)
ARM msvc v19.0 (ex-WINE)
ARM msvc v19.10 (ex-WINE)
ARM msvc v19.14 (ex-WINE)
ARM64 GCC 10.2.0
ARM64 GCC 10.3.0
ARM64 GCC 10.4.0
ARM64 GCC 10.5.0
ARM64 GCC 11.1.0
ARM64 GCC 11.2.0
ARM64 GCC 11.3.0
ARM64 GCC 11.4.0
ARM64 GCC 12.1.0
ARM64 GCC 12.2.0
ARM64 GCC 12.3.0
ARM64 GCC 12.4.0
ARM64 GCC 12.5.0
ARM64 GCC 13.1.0
ARM64 GCC 13.2.0
ARM64 GCC 13.3.0
ARM64 GCC 13.4.0
ARM64 GCC 14.1.0
ARM64 GCC 14.2.0
ARM64 GCC 14.3.0
ARM64 GCC 15.1.0
ARM64 GCC 15.2.0
ARM64 GCC 4.9.4
ARM64 GCC 5.4
ARM64 GCC 5.5.0
ARM64 GCC 6.3
ARM64 GCC 6.4.0
ARM64 GCC 7.3.0
ARM64 GCC 7.5.0
ARM64 GCC 8.2.0
ARM64 GCC 8.5.0
ARM64 GCC 9.3.0
ARM64 GCC 9.4.0
ARM64 GCC 9.5.0
ARM64 GCC trunk
ARM64 Morello GCC 10.1.0 Alpha 1
ARM64 Morello GCC 10.1.2 Alpha 2
ARM64 msvc v19.14 (ex-WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 12.5.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 13.4.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 14.3.0
AVR gcc 15.1.0
AVR gcc 15.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF clang 20.1.0
BPF clang 21.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc 13.3.0
BPF gcc 13.4.0
BPF gcc 14.1.0
BPF gcc 14.2.0
BPF gcc 14.3.0
BPF gcc 15.1.0
BPF gcc 15.2.0
BPF gcc trunk
C2Rust (master)
Chibicc 2020-12-07
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
HPPA gcc 14.3.0
HPPA gcc 15.1.0
HPPA gcc 15.2.0
K1C gcc 7.4
K1C gcc 7.5
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
KVX ACB 5.2.0 (GCC 13.2.1)
LC3 (trunk)
M68K clang (trunk)
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 13.4.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68K gcc 14.3.0
M68K gcc 15.1.0
M68K gcc 15.2.0
MRISC32 gcc (trunk)
MSP430 gcc 12.1.0
MSP430 gcc 12.2.0
MSP430 gcc 12.3.0
MSP430 gcc 12.4.0
MSP430 gcc 12.5.0
MSP430 gcc 13.1.0
MSP430 gcc 13.2.0
MSP430 gcc 13.3.0
MSP430 gcc 13.4.0
MSP430 gcc 14.1.0
MSP430 gcc 14.2.0
MSP430 gcc 14.3.0
MSP430 gcc 15.1.0
MSP430 gcc 15.2.0
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
ORCA/C 2.1.0
ORCA/C 2.2.0
ORCA/C 2.2.1
POWER64 gcc 11.2.0
POWER64 gcc 12.1.0
POWER64 gcc 12.2.0
POWER64 gcc 12.3.0
POWER64 gcc 12.4.0
POWER64 gcc 12.5.0
POWER64 gcc 13.1.0
POWER64 gcc 13.2.0
POWER64 gcc 13.3.0
POWER64 gcc 13.4.0
POWER64 gcc 14.1.0
POWER64 gcc 14.2.0
POWER64 gcc 14.3.0
POWER64 gcc 15.1.0
POWER64 gcc 15.2.0
POWER64 gcc trunk
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 12.5.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 13.4.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 14.3.0
RISC-V (32-bits) gcc 15.1.0
RISC-V (32-bits) gcc 15.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 12.5.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 13.4.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 14.3.0
RISC-V (64-bits) gcc 15.1.0
RISC-V (64-bits) gcc 15.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 20.1.0
RISC-V rv32gc clang 21.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 20.1.0
RISC-V rv64gc clang 21.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SDCC 4.0.0
SDCC 4.1.0
SDCC 4.2.0
SDCC 4.3.0
SDCC 4.4.0
SDCC 4.5.0
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 12.5.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 13.4.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC LEON gcc 14.3.0
SPARC LEON gcc 15.1.0
SPARC LEON gcc 15.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 12.5.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 13.4.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC gcc 14.3.0
SPARC gcc 15.1.0
SPARC gcc 15.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 12.5.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 13.4.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
SPARC64 gcc 14.3.0
SPARC64 gcc 15.1.0
SPARC64 gcc 15.2.0
TCC (trunk)
TCC 0.9.27
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 12.5.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 13.4.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI C6x gcc 14.3.0
TI C6x gcc 15.1.0
TI C6x gcc 15.2.0
TI CL430 21.6.1
Tricore gcc 11.3.0 (EEESlab)
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
VAX gcc NetBSDELF 12.4.0 (Apr 16 05:27 2025)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 14.2.0 (20241119)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 14.2.0 (20241119)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 14.2.0 (20241119)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.41 VS17.11
arm64 msvc v19.42 VS17.12
arm64 msvc v19.43 VS17.13
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 20.1.0
armv7-a clang 21.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 12.0.1
armv8-a clang 13.0.0
armv8-a clang 13.0.1
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 20.1.0
armv8-a clang 21.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
clang 12 for DPU (rel 2023.2.0)
cproc-master
ez80-clang 15.0.0
ez80-clang 15.0.7
llvm-mos commander X16
llvm-mos commodore 64
llvm-mos mega65
llvm-mos nes-cnrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos osi-c1p
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 12.5.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 13.4.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
loongarch64 gcc 14.3.0
loongarch64 gcc 15.1.0
loongarch64 gcc 15.2.0
mips (el) gcc 12.1.0
mips (el) gcc 12.2.0
mips (el) gcc 12.3.0
mips (el) gcc 12.4.0
mips (el) gcc 12.5.0
mips (el) gcc 13.1.0
mips (el) gcc 13.2.0
mips (el) gcc 13.3.0
mips (el) gcc 13.4.0
mips (el) gcc 14.1.0
mips (el) gcc 14.2.0
mips (el) gcc 14.3.0
mips (el) gcc 15.1.0
mips (el) gcc 15.2.0
mips (el) gcc 4.9.4
mips (el) gcc 5.4
mips (el) gcc 5.5.0
mips (el) gcc 9.5.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips clang 20.1.0
mips clang 21.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 12.5.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 13.4.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 14.3.0
mips gcc 15.1.0
mips gcc 15.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 12.5.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 13.4.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 14.3.0
mips64 (el) gcc 15.1.0
mips64 (el) gcc 15.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 clang 20.1.0
mips64 clang 21.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 12.5.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 13.4.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 14.3.0
mips64 gcc 15.1.0
mips64 gcc 15.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mips64el clang 20.1.0
mips64el clang 21.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel clang 20.1.0
mipsel clang 21.1.0
movfuscator (trunk)
nanoMIPS gcc 6.3.0
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 12.5.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 13.4.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 14.3.0
power gcc 15.1.0
power gcc 15.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 12.5.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 13.4.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 14.3.0
power64le gcc 15.1.0
power64le gcc 15.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
ppci 0.5.5
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 12.5.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 13.4.0
s390x gcc 14.1.0
s390x gcc 14.2.0
s390x gcc 14.3.0
s390x gcc 15.1.0
s390x gcc 15.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 12.5.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 13.4.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 14.3.0
sh gcc 15.1.0
sh gcc 15.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (ex-WINE)
x64 msvc v19.10 (ex-WINE)
x64 msvc v19.14 (ex-WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.41 VS17.11
x64 msvc v19.42 VS17.12
x64 msvc v19.43 VS17.13
x64 msvc v19.latest
x86 CompCert 3.10
x86 CompCert 3.11
x86 CompCert 3.12
x86 CompCert 3.9
x86 gcc 1.27
x86 msvc v19.0 (ex-WINE)
x86 msvc v19.10 (ex-WINE)
x86 msvc v19.14 (ex-WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.41 VS17.11
x86 msvc v19.42 VS17.12
x86 msvc v19.43 VS17.13
x86 msvc v19.latest
x86 nvc 24.11
x86 nvc 24.9
x86 nvc 25.1
x86 nvc 25.3
x86 nvc 25.5
x86 nvc 25.7
x86 tendra (trunk)
x86-64 clang (assertions trunk)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 15.0.0
x86-64 clang 16.0.0
x86-64 clang 17.0.1
x86-64 clang 18.1.0
x86-64 clang 19.1.0
x86-64 clang 20.1.0
x86-64 clang 21.1.0
x86-64 clang 3.0.0
x86-64 clang 3.1
x86-64 clang 3.2
x86-64 clang 3.3
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.7
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.1
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.3 (assertions)
x86-64 gcc 10.4
x86-64 gcc 10.4 (assertions)
x86-64 gcc 10.5
x86-64 gcc 10.5 (assertions)
x86-64 gcc 11.1
x86-64 gcc 11.1 (assertions)
x86-64 gcc 11.2
x86-64 gcc 11.2 (assertions)
x86-64 gcc 11.3
x86-64 gcc 11.3 (assertions)
x86-64 gcc 11.4
x86-64 gcc 11.4 (assertions)
x86-64 gcc 12.1
x86-64 gcc 12.1 (assertions)
x86-64 gcc 12.2
x86-64 gcc 12.2 (assertions)
x86-64 gcc 12.3
x86-64 gcc 12.3 (assertions)
x86-64 gcc 12.4
x86-64 gcc 12.4 (assertions)
x86-64 gcc 12.5
x86-64 gcc 12.5 (assertions)
x86-64 gcc 13.1
x86-64 gcc 13.1 (assertions)
x86-64 gcc 13.2
x86-64 gcc 13.2 (assertions)
x86-64 gcc 13.3
x86-64 gcc 13.3 (assertions)
x86-64 gcc 13.4
x86-64 gcc 13.4 (assertions)
x86-64 gcc 14.1
x86-64 gcc 14.1 (assertions)
x86-64 gcc 14.2
x86-64 gcc 14.2 (assertions)
x86-64 gcc 14.3
x86-64 gcc 14.3 (assertions)
x86-64 gcc 15.1
x86-64 gcc 15.1 (assertions)
x86-64 gcc 15.2
x86-64 gcc 15.2 (assertions)
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx (latest)
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2024.0.0
x86_64 CompCert 3.10
x86_64 CompCert 3.11
x86_64 CompCert 3.12
x86_64 CompCert 3.9
z180-clang 15.0.0
z180-clang 15.0.7
z80-clang 15.0.0
z80-clang 15.0.7
z88dk 2.2
zig cc 0.10.0
zig cc 0.11.0
zig cc 0.12.0
zig cc 0.12.1
zig cc 0.13.0
zig cc 0.14.0
zig cc 0.14.1
zig cc 0.15.1
zig cc 0.6.0
zig cc 0.7.0
zig cc 0.7.1
zig cc 0.8.0
zig cc 0.9.0
zig cc trunk
Options
Source code
#define WIN32_LEAN_AND_MEAN #define NOMINMAX #include <Windows.h> #define WRITER_BUFFER_SIZE 4096 #define FMT_LOG_ERROR(message) fmt_log_error(message) #define FMT_ALLOC fmt_dumb_alloc #define FMT_DEALLOC fmt_dumb_dealloc typedef _Bool bool; enum { false, true }; typedef unsigned char u8; typedef char i8; typedef unsigned short u16; typedef short i16; typedef unsigned int u32; typedef int i32; typedef unsigned long long u64; typedef long long i64; typedef u64 usize; typedef i64 isize; enum { u4_0000, u4_0001, u4_0010, u4_0011, u4_0100, u4_0101, u4_0110, u4_0111, u4_1000, u4_1001, u4_1010, u4_1011, u4_1100, u4_1101, u4_1110, u4_1111, }; #define u8_bin(high, low) (((u8) u4_##high << 4) | (u8) u4_##low) isize isize_min(isize self, isize other) { return self < other ? self : other; } isize isize_max(isize self, isize other) { return self > other ? self : other; } void copy_nonoverlapping(void const *source_void, void *dest_void, isize size) { u8 const *source = (u8 const *) source_void; u8 *dest = (u8 *) dest_void; for (isize i = 0; i < size; i += 1) { dest[i] = source[i]; } } #define ARRAY_SIZE(array) ((isize) sizeof(array) / sizeof((array)[0])) isize c_string_size(char const *string) { char const *string_iter = string; while (*string_iter != '\0') { string_iter += 1; } return string_iter - string; } typedef struct { u8 const *data; isize size; } StringView; #define SV(string_literal) \ (StringView){(u8 const *) (string_literal), (isize) sizeof(string_literal) - 1} isize sv_utf8_size(StringView string) { isize utf8_size = 0; u8 const *string_iter = string.data, *string_end = string.data + string.size; while (string_iter < string_end) { if ((*string_iter & u8_bin(1000, 0000)) == 0) { string_iter += 1; } else if ((*string_iter & u8_bin(1110, 0000)) == u8_bin(1100, 0000)) { string_iter += 2; } else if ((*string_iter & u8_bin(1111, 0000)) == u8_bin(1110, 0000)) { string_iter += 3; } else { string_iter += 4; } utf8_size += 1; } return utf8_size; } bool sv_equals(StringView self, StringView other) { if (self.size != other.size) { return false; } for (isize i = 0; i < self.size; i += 1) { if (self.data[i] != other.data[i]) { return false; } } return true; } StringView sv_from_c_string(char const *string) { return (StringView) { .data = (u8 const *) string, .size = c_string_size(string), }; } typedef u32 CodePoint; isize cp_utf8_size(CodePoint code_point) { if (code_point < 0x80) { return 1; } else if (code_point < 0x800) { return 2; } else if (code_point < 0x10000) { return 3; } else { return 4; } } bool cp_is_high_surrogate(CodePoint code_point) { return 0xd800 <= code_point && code_point < 0xdc00; } void fmt_log_error(char const *message) { HANDLE error_output = GetStdHandle(STD_ERROR_HANDLE); UINT old_code_page = GetConsoleOutputCP(); SetConsoleOutputCP(CP_UTF8); char const message_label[] = "[ERROR] "; WriteFile(error_output, message_label, sizeof(message_label) - 1, NULL, NULL); WriteFile(error_output, message, c_string_size(message), NULL, NULL); char const new_line[] = "\n"; WriteFile(error_output, new_line, sizeof(new_line) - 1, NULL, NULL); SetConsoleOutputCP(old_code_page); } void *fmt_dumb_alloc(isize size) { void *ptr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (ptr == NULL) { FMT_LOG_ERROR("Failed to allocate memory"); ExitProcess(1); } return ptr; } void fmt_dumb_dealloc(void *ptr) { VirtualFree(ptr, 0, MEM_RELEASE); } typedef struct { u8 *data; isize size; isize capacity; } Buffer; void buffer_create(isize capacity, Buffer *buffer) { buffer->data = FMT_ALLOC(capacity); buffer->capacity = capacity; buffer->size = 0; } isize buffer_write(Buffer *buffer, u8 const *data, isize size) { u8 *buffer_begin = buffer->data + buffer->size; u8 *buffer_end = buffer->data + buffer->capacity; isize bytes_written = isize_max(isize_min(size, buffer_end - buffer_begin), 0); copy_nonoverlapping(data, buffer_begin, bytes_written); buffer->size += bytes_written; return bytes_written; } bool buffer_is_full(Buffer *buffer) { return buffer->size == buffer->capacity; } void buffer_reset(Buffer *buffer) { buffer->size = 0; } void buffer_destroy(Buffer *buffer) { FMT_DEALLOC(buffer->data); } typedef bool (*WriteFunction)(void *writer_data, u8 const *data, isize size, isize *bytes_written); typedef bool (*FlushFunction)(void *writer_data); typedef struct { void *writer_data; WriteFunction write; FlushFunction flush; } Writer; bool writer_write(Writer *writer, u8 const *data, isize size, isize *bytes_written) { return writer->write(writer->writer_data, data, size, bytes_written); } bool writer_flush(Writer *writer) { return writer->flush(writer->writer_data); } typedef struct { HANDLE file; Buffer buffer; } FileWriter; bool file_writer_flush(void *file_writer_void) { FileWriter *file_writer = (FileWriter *) file_writer_void; bool file_written = WriteFile( file_writer->file, file_writer->buffer.data, file_writer->buffer.size, NULL, NULL ); buffer_reset(&file_writer->buffer); return file_written; } bool file_writer_write( void *file_writer_void, u8 const *data, isize size, isize *bytes_written_total ) { FileWriter *file_writer = (FileWriter *) file_writer_void; *bytes_written_total = 0; isize data_size_left = size; u8 const *data_iter = data; while (data_size_left > 0) { isize bytes_written = buffer_write(&file_writer->buffer, data_iter, data_size_left); data_iter += bytes_written; data_size_left -= bytes_written; *bytes_written_total += bytes_written; if (buffer_is_full(&file_writer->buffer)) { if (!file_writer_flush(file_writer)) { return false; } } else if (bytes_written == 0) { return false; } } return true; } void file_writer_create(HANDLE file, Writer *writer) { FileWriter *file_writer = FMT_ALLOC(sizeof(FileWriter)); file_writer->file = file; buffer_create(WRITER_BUFFER_SIZE, &file_writer->buffer); writer->writer_data = file_writer; writer->write = file_writer_write; writer->flush = file_writer_flush; } void file_writer_destroy(Writer *writer) { FileWriter *file_writer = (FileWriter *) writer->writer_data; buffer_destroy(&file_writer->buffer); FMT_DEALLOC(file_writer); } static isize console_writer_created_times = 0; static UINT old_console_output_code_page = 0; void console_writer_create(Writer *writer) { HANDLE console_output = GetStdHandle(STD_OUTPUT_HANDLE); if (console_output == INVALID_HANDLE_VALUE) { FMT_LOG_ERROR("Failed to retrieve a console handle"); ExitProcess(1); } file_writer_create(console_output, writer); console_writer_created_times += 1; if (console_writer_created_times == 1) { old_console_output_code_page = GetConsoleOutputCP(); SetConsoleOutputCP(CP_UTF8); } } void console_writer_destroy(Writer *writer) { file_writer_destroy(writer); console_writer_created_times -= 1; if (console_writer_created_times == 0) { SetConsoleOutputCP(old_console_output_code_page); } } typedef Buffer StringBufferWriter; bool string_buffer_writer_write( void *string_writer_void, u8 const *data, isize size, isize *bytes_written_total ) { StringBufferWriter *string_writer = (StringBufferWriter *) string_writer_void; isize bytes_written = buffer_write(string_writer, data, size); if (bytes_written < size) { return false; } return true; } bool string_buffer_writer_flush(void *string_writer_void) { return true; } void string_buffer_writer_create(char *string, isize capacity, Writer *writer) { StringBufferWriter *string_writer = FMT_ALLOC(sizeof(StringBufferWriter)); string_writer->data = (u8 *) string; string_writer->capacity = capacity; writer->writer_data = string_writer; writer->write = string_buffer_writer_write; writer->flush = string_buffer_writer_flush; } void string_buffer_writer_destroy(Writer *writer) { FMT_DEALLOC(writer->writer_data); } typedef enum { FORMAT_ARG_int, FORMAT_ARG_bool, FORMAT_ARG_char, FORMAT_ARG_CodePoint, FORMAT_ARG_CString, FORMAT_ARG_WideCString, FORMAT_ARG_StringView, FORMAT_ARG_ptr, } FormatArgKind; typedef enum { FMT_ALIGN_RIGHT, FMT_ALIGN_CENTER, FMT_ALIGN_LEFT, } FormatAlignment; #define FMT_COMMON_PARAMS_DEFINE \ isize pad; \ char padder; \ FormatAlignment align #define FMT_COMMON_PARAMS_EXTRACT(fmt_arg) \ (&(FormatCommonParams) { \ .pad = (fmt_arg)->pad, \ .padder = (fmt_arg)->padder, \ .align = (fmt_arg)->align, \ }) typedef struct { isize pad; char padder; FormatAlignment align; } FormatCommonParams; typedef struct { u64 value; isize size; bool is_negative; FMT_COMMON_PARAMS_DEFINE; bool plus; bool uppercase; bool hex; bool octal; bool bin; } FormatArg_int; typedef struct { bool value; FMT_COMMON_PARAMS_DEFINE; } FormatArg_bool; typedef struct { char value; } FormatArg_char; typedef struct { CodePoint value; } FormatArg_CodePoint; typedef struct { char const *value; FMT_COMMON_PARAMS_DEFINE; } FormatArg_CString; typedef struct { StringView value; FMT_COMMON_PARAMS_DEFINE; } FormatArg_StringView; typedef struct { u16 const *value; FMT_COMMON_PARAMS_DEFINE; } FormatArg_WideCString; typedef isize (*FormatPtrFunction)(Writer *writer, void const *ptr); typedef struct { void const *value; FormatPtrFunction fmt; } FormatArg_ptr; typedef struct { FormatArgKind kind; char const *name; union { FormatArg_int int_arg; FormatArg_bool bool_arg; FormatArg_char char_arg; FormatArg_CodePoint CodePoint_arg; FormatArg_CString CString_arg; FormatArg_WideCString WideCString_arg; FormatArg_StringView StringView_arg; FormatArg_ptr ptr_arg; } as; } FormatArg; #define FMT(type, value, ...) FMT_##type(type, NULL, value, __VA_ARGS__) #define FMT_KEY(type, name, value, ...) FMT_##type(type, #name, value, __VA_ARGS__) #define FMT_PLAIN_VALUE(type, name_, value_, ...) \ (FormatArg) { \ .kind = FORMAT_ARG_##type, .name = (name_), .as.type##_arg = { \ .value = (value_), \ __VA_ARGS__ \ } \ } #define FMT_bool(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_char(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_CodePoint(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_CString(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_WideCString(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_StringView(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_ptr(type, name, value, ...) FMT_PLAIN_VALUE(type, name, value, __VA_ARGS__) #define FMT_int(type, name_, value_, ...) \ (FormatArg) { \ .kind = FORMAT_ARG_int, .name = (name_), \ .as.int_arg = { \ .value = (value_) < 0 ? (u64) (-(value_)) : (u64) (value_), \ .size = sizeof(type), \ .is_negative = (value_) < 0, \ __VA_ARGS__ \ }, \ } #define FMT_u8(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_i8(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_u16(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_i16(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_u32(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_i32(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_u64(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) #define FMT_i64(type, name, value, ...) FMT_int(type, name, value, __VA_ARGS__) isize fmt_write_char(Writer *writer, char value) { if (writer == NULL) { return sizeof(char); } isize bytes_written = 0; if (!writer_write(writer, (u8 const *) &value, sizeof(char), &bytes_written)) { FMT_LOG_ERROR("An underlying writer returned an error"); ExitProcess(1); } return bytes_written; } isize fmt_write_char_repeat(Writer *writer, isize repeat_times, char value) { if (writer == NULL) { return repeat_times * sizeof(char); } u8 buffer[WRITER_BUFFER_SIZE]; for (isize i = 0; i < isize_min(repeat_times, ARRAY_SIZE(buffer)); i += 1) { buffer[i] = value; } isize bytes_written_total = 0; isize repeat_times_left = repeat_times; while (repeat_times_left > 0) { isize bytes_written = 0; if (!writer_write( writer, buffer, isize_min(repeat_times_left, ARRAY_SIZE(buffer)), &bytes_written )) { FMT_LOG_ERROR("An underlying writer returned an error"); ExitProcess(1); } bytes_written_total += bytes_written; repeat_times_left = isize_max(repeat_times_left - ARRAY_SIZE(buffer), 0); } return bytes_written_total; } isize fmt_write_code_point(Writer *writer, CodePoint code_point) { if (writer == NULL) { return cp_utf8_size(code_point); } u8 utf8_encoded_data[4]; if (code_point < 0x80) { utf8_encoded_data[0] = (u8) code_point; } else if (code_point < 0x800) { utf8_encoded_data[0] = u8_bin(1100, 0000) | (u8) ((code_point >> 6) & (CodePoint) u8_bin(0001, 1111)); utf8_encoded_data[1] = u8_bin(1000, 0000) | (u8) ((code_point >> 0) & (CodePoint) u8_bin(0011, 1111)); } else if (code_point < 0x10000) { utf8_encoded_data[0] = u8_bin(1110, 0000) | (u8) ((code_point >> 12) & (CodePoint) u8_bin(0000, 1111)); utf8_encoded_data[1] = u8_bin(1000, 0000) | (u8) ((code_point >> 6) & (CodePoint) u8_bin(0011, 1111)); utf8_encoded_data[2] = u8_bin(1000, 0000) | (u8) ((code_point >> 0) & (CodePoint) u8_bin(0011, 1111)); } else { utf8_encoded_data[0] = u8_bin(1111, 0000) | (u8) ((code_point >> 18) & (CodePoint) u8_bin(0000, 0111)); utf8_encoded_data[1] = u8_bin(1000, 0000) | (u8) ((code_point >> 12) & (CodePoint) u8_bin(0011, 1111)); utf8_encoded_data[2] = u8_bin(1000, 0000) | (u8) ((code_point >> 6) & (CodePoint) u8_bin(0011, 1111)); utf8_encoded_data[3] = u8_bin(1000, 0000) | (u8) ((code_point >> 0) & (CodePoint) u8_bin(0011, 1111)); } isize bytes_written = 0; if (!writer_write(writer, utf8_encoded_data, cp_utf8_size(code_point), &bytes_written)) { FMT_LOG_ERROR("An underlying writer returned an error"); ExitProcess(1); } return bytes_written; } isize fmt_write_left_padding( Writer *writer, isize content_size, FormatCommonParams *common_params ) { char padder_char = common_params->padder != 0 ? common_params->padder : ' '; isize padding_amount = 0; if (common_params->align == FMT_ALIGN_RIGHT) { padding_amount = isize_max(common_params->pad - content_size, 0); } else if (common_params->align == FMT_ALIGN_CENTER) { isize total_padding_amount = isize_max(common_params->pad - content_size, 0); padding_amount = total_padding_amount - total_padding_amount / 2; } if (writer == NULL) { return padding_amount * sizeof(char); } return fmt_write_char_repeat(writer, padding_amount, padder_char); } isize fmt_write_right_padding( Writer *writer, isize content_size, FormatCommonParams *common_params ) { char padder_char = common_params->padder != 0 ? common_params->padder : ' '; isize padding_amount = 0; if (common_params->align == FMT_ALIGN_LEFT) { padding_amount = isize_max(common_params->pad - content_size, 0); } else if (common_params->align == FMT_ALIGN_CENTER) { isize total_padding_amount = isize_max(common_params->pad - content_size, 0); padding_amount = total_padding_amount / 2; } if (writer == NULL) { return padding_amount * sizeof(char); } return fmt_write_char_repeat(writer, padding_amount, padder_char); } isize fmt_write_plain_sv(Writer *writer, StringView sv) { if (writer == NULL) { return sv.size; } isize bytes_written = 0; if (!writer_write(writer, (u8 const *) sv.data, sv.size, &bytes_written)) { FMT_LOG_ERROR("An underlying writer returned an error"); ExitProcess(1); } return bytes_written; } isize fmt_write_sv(Writer *writer, StringView sv, FormatCommonParams *common_params) { isize sv_size_in_chars = sv_utf8_size(sv); isize bytes_written = 0; bytes_written += fmt_write_left_padding(writer, sv_size_in_chars, common_params); bytes_written += fmt_write_plain_sv(writer, sv); bytes_written += fmt_write_right_padding(writer, sv_size_in_chars, common_params); return bytes_written; } isize fmt_write_bool(Writer *writer, FormatArg_bool const *fmt_arg) { if (writer == NULL) { if (fmt_arg->value) { return SV("true").size; } else { return SV("false").size; } } if (fmt_arg->value) { return fmt_write_sv(writer, SV("true"), FMT_COMMON_PARAMS_EXTRACT(fmt_arg)); } else { return fmt_write_sv(writer, SV("false"), FMT_COMMON_PARAMS_EXTRACT(fmt_arg)); } } isize fmt_write_c_string(Writer *writer, FormatArg_CString const *fmt_arg) { StringView sv = { .size = c_string_size(fmt_arg->value), .data = (u8 const *) fmt_arg->value, }; return fmt_write_sv(writer, sv, FMT_COMMON_PARAMS_EXTRACT(fmt_arg)); } isize fmt_write_wide_c_string(Writer *writer, FormatArg_WideCString const *fmt_arg) { isize string_size_in_chars = 0; { isize utf8_size = 0; u16 const *wide_string_iter = fmt_arg->value; while (*wide_string_iter != L'\0') { if (cp_is_high_surrogate(*wide_string_iter)) { utf8_size += 4; wide_string_iter += 2; } else { utf8_size += cp_utf8_size((CodePoint) *wide_string_iter); wide_string_iter += 1; } string_size_in_chars += 1; } if (writer == NULL) { return utf8_size; } } isize bytes_written = 0; bytes_written += fmt_write_left_padding(writer, string_size_in_chars, FMT_COMMON_PARAMS_EXTRACT(fmt_arg)); u8 utf8_buffer[WRITER_BUFFER_SIZE]; isize utf8_size = 0; u16 const *wide_string_iter = fmt_arg->value, *wide_string_begin = fmt_arg->value; while (*wide_string_iter != L'\0') { if (cp_is_high_surrogate(*wide_string_iter)) { utf8_size += 4; wide_string_iter += 2; } else { utf8_size += cp_utf8_size((CodePoint) *wide_string_iter); wide_string_iter += 1; } if ((isize) sizeof(utf8_buffer) - utf8_size < 4 || *wide_string_iter == L'\0') { WideCharToMultiByte( CP_UTF8, 0, wide_string_begin, wide_string_iter - wide_string_begin, (char *) utf8_buffer, sizeof(utf8_buffer), NULL, NULL ); bytes_written += fmt_write_plain_sv(writer, (StringView) {utf8_buffer, utf8_size}); wide_string_begin = wide_string_iter; utf8_size = 0; } } bytes_written += fmt_write_right_padding(writer, string_size_in_chars, FMT_COMMON_PARAMS_EXTRACT(fmt_arg)); return bytes_written; } isize fmt_write_int(Writer *writer, FormatArg_int const *fmt_arg) { u8 alphabet_lowercase[] = "0123456789abcdef", alphabet_uppercase[] = "0123456789ABCDEF"; u8 *alphabet = alphabet_lowercase; if (fmt_arg->uppercase) { alphabet = alphabet_uppercase; } u64 base = 10; if (fmt_arg->bin) { base = 2; } else if (fmt_arg->hex) { base = 16; } else if (fmt_arg->octal) { base = 8; } u64 unsigned_value = fmt_arg->value; bool is_negative = fmt_arg->is_negative; if (base != 10 && is_negative) { i64 signed_value = (i64) (-unsigned_value); copy_nonoverlapping((u8 const *) &signed_value, (u8 *) &unsigned_value, sizeof(u64)); if (fmt_arg->size < sizeof(u64)) { unsigned_value = unsigned_value & ((1LLU << fmt_arg->size * 8) - 1); } is_negative = false; } u8 string_buffer[64]; u8 *string_begin = string_buffer + sizeof(string_buffer), *string_end = string_buffer + sizeof(string_buffer); if (unsigned_value == 0) { string_begin -= 1; *string_begin = alphabet[0]; } else { while (unsigned_value > 0) { string_begin -= 1; *string_begin = alphabet[unsigned_value % base]; unsigned_value /= base; } } if (is_negative) { string_begin -= 1; *string_begin = '-'; } else if (fmt_arg->plus && fmt_arg->value != 0) { string_begin -= 1; *string_begin = '+'; } StringView sv = { .data = string_begin, .size = string_end - string_begin, }; return fmt_write_sv(writer, sv, FMT_COMMON_PARAMS_EXTRACT(fmt_arg)); } isize fmt_write_ptr(Writer *writer, FormatArg_ptr const *ptr_arg) { if (ptr_arg->fmt == NULL) { FMT_LOG_ERROR("Custom formatter function is not specified"); ExitProcess(1); } return ptr_arg->fmt(writer, ptr_arg->value); } FormatArg const * fmt_args_get_by_name(FormatArg const *haystack, isize haystack_size, StringView needle) { for (isize i = 0; i < haystack_size; i += 1) { if (haystack[i].name == NULL) { continue; } if (sv_equals(sv_from_c_string(haystack[i].name), needle)) { return &haystack[i]; } } return NULL; } isize fmt_write_impl( Writer *writer, char const *format, FormatArg const *format_args, isize format_args_size ) { FormatArg const *format_args_iter = format_args, *format_args_end = format_args + format_args_size; isize bytes_written = 0; char const *format_iter = format, *format_begin = format; while (*format_iter != '\0') { if (*format_iter == '{') { bytes_written += fmt_write_plain_sv( writer, (StringView) {(u8 const *) format_begin, format_iter - format_begin} ); if (*(format_iter + 1) == '{') { bytes_written += fmt_write_char(writer, '{'); format_iter += 2; format_begin = format_iter; continue; } format_iter += 1; format_begin = format_iter; if (*format_iter == '\0') { FMT_LOG_ERROR("An unpaired '{' encountered in the format string"); ExitProcess(1); } char const *arg_name_iter = format_iter, *arg_name_begin = format_iter; while (*arg_name_iter != '}') { arg_name_iter += 1; } StringView arg_name = {(u8 const *) arg_name_begin, arg_name_iter - arg_name_begin}; FormatArg const *current_format_arg; if (arg_name.size == 0) { while (format_args_iter < format_args_end) { if (format_args_iter->name == NULL) { break; } else { format_args_iter += 1; } } if (format_args_iter == format_args_end) { FMT_LOG_ERROR("Not enough format arguments"); ExitProcess(1); } current_format_arg = format_args_iter; format_args_iter += 1; } else { current_format_arg = fmt_args_get_by_name(format_args, format_args_size, arg_name); if (current_format_arg == NULL) { FMT_LOG_ERROR("Format arg is not found by name"); ExitProcess(1); } } switch (current_format_arg->kind) { case FORMAT_ARG_int: { bytes_written += fmt_write_int(writer, ¤t_format_arg->as.int_arg); } break; case FORMAT_ARG_bool: { bytes_written += fmt_write_bool(writer, ¤t_format_arg->as.bool_arg); } break; case FORMAT_ARG_char: { bytes_written += fmt_write_char(writer, current_format_arg->as.char_arg.value); } break; case FORMAT_ARG_CodePoint: { bytes_written += fmt_write_code_point(writer, current_format_arg->as.CodePoint_arg.value); } break; case FORMAT_ARG_CString: { bytes_written += fmt_write_c_string(writer, ¤t_format_arg->as.CString_arg); } break; case FORMAT_ARG_WideCString: { bytes_written += fmt_write_wide_c_string(writer, ¤t_format_arg->as.WideCString_arg); } break; case FORMAT_ARG_StringView: { bytes_written += fmt_write_sv( writer, current_format_arg->as.StringView_arg.value, FMT_COMMON_PARAMS_EXTRACT(¤t_format_arg->as.StringView_arg) ); } break; case FORMAT_ARG_ptr: { bytes_written += fmt_write_ptr(writer, ¤t_format_arg->as.ptr_arg); } break; } format_iter = arg_name_iter + 1; format_begin = arg_name_iter + 1; } else if (*format_iter == '}') { bytes_written += fmt_write_plain_sv( writer, (StringView) {(u8 const *) format_begin, format_iter - format_begin} ); if (*(format_iter + 1) != '}') { ExitProcess(1); } bytes_written += fmt_write_char(writer, '}'); format_iter += 2; format_begin = format_iter; } else { format_iter += 1; } } if (format_begin < format_iter) { bytes_written += fmt_write_plain_sv( writer, (StringView) {(u8 const *) format_begin, format_iter - format_begin} ); } return bytes_written; } #define fmt_write(writer, format, ...) \ fmt_write_impl( \ writer, format, (FormatArg[]) {__VA_ARGS__}, ARRAY_SIZE(((FormatArg[]) {__VA_ARGS__})) \ ) isize fmt_console_write_impl( char const *format, FormatArg const *format_args, isize format_args_size ) { HANDLE console_output = GetStdHandle(STD_OUTPUT_HANDLE); if (console_output == INVALID_HANDLE_VALUE) { FMT_LOG_ERROR("Failed to retrieve a console handle"); ExitProcess(1); } UINT old_console_output_code_page = GetConsoleOutputCP(); SetConsoleOutputCP(CP_UTF8); u8 buffer_data[WRITER_BUFFER_SIZE]; FileWriter file_writer = { .file = GetStdHandle(STD_OUTPUT_HANDLE), .buffer = {.data = buffer_data, .size = 0, .capacity = sizeof(buffer_data)}, }; Writer writer = { .writer_data = &file_writer, .write = file_writer_write, .flush = file_writer_flush, }; isize bytes_written = fmt_write_impl(&writer, format, format_args, format_args_size); writer_flush(&writer); SetConsoleOutputCP(old_console_output_code_page); return bytes_written; } #define fmt_console(format, ...) \ fmt_console_write_impl( \ format, (FormatArg[]) {__VA_ARGS__}, ARRAY_SIZE(((FormatArg[]) {__VA_ARGS__})) \ ) isize fmt_string_write_impl( u8 *string, isize capacity, char const *format, FormatArg const *format_args, isize format_args_size ) { if (string == NULL) { return fmt_write_impl(NULL, format, format_args, format_args_size); } StringBufferWriter string_writer = { .data = (u8 *) string, .size = 0, .capacity = capacity, }; Writer writer = { .writer_data = &string_writer, .write = string_buffer_writer_write, .flush = string_buffer_writer_flush, }; return fmt_write_impl(&writer, format, format_args, format_args_size); } #define fmt_string(string, capacity, format, ...) \ fmt_string_write_impl( \ string, \ capacity, \ format, \ (FormatArg[]) {__VA_ARGS__}, \ ARRAY_SIZE(((FormatArg[]) {__VA_ARGS__})) \ ) typedef struct { i32 x, y, z; } IVec3; isize fmt_ivec3(Writer *writer, void const *vector_void) { IVec3 const *vector = (IVec3 const *) vector_void; return fmt_write( writer, "vec3({}, {}, {})", FMT(i32, vector->x), FMT(i32, vector->y), FMT(i32, vector->z), ); } i32 main(void) { fmt_console( "Formatting integers test:\n" " Positive i32 = {}\n" " Negative i64 = {}\n" " Zero = {}\n" " Positive hex u32 = 0x{}\n" " Negative bin i64 = 0b{}\n" " Padded u64 hex = 0x{}\n" "\n", FMT(i32, 12345, .plus = true), FMT(i64, -123456789LL), FMT(i8, 0), FMT(u32, 0xdeadbabe, .hex = true, .uppercase = true), FMT(i64, -42, .bin = true), FMT(u64, 12345678912345LLU, .hex = true, .pad = 16, .padder = '0'), ); fmt_console( "|{}|{}|{}|\n" "|{bar}|{bar}|{bar}|\n" "|{f}|{f}|{}|\n" "|{f}|{t}|{}|\n" "|{t}|{f}|{}|\n" "|{t}|{t}|{}|\n" "\n", FMT(CString, "A", .pad = 9, .align = FMT_ALIGN_CENTER), FMT(CString, "B", .pad = 9, .align = FMT_ALIGN_CENTER), FMT(CString, "A ^ B", .pad = 9, .align = FMT_ALIGN_CENTER), FMT(bool, false ^ false, .pad = 9, .align = FMT_ALIGN_CENTER), FMT(bool, false ^ true, .pad = 9, .align = FMT_ALIGN_CENTER), FMT(bool, true ^ false, .pad = 9, .align = FMT_ALIGN_CENTER), FMT(bool, true ^ true, .pad = 9, .align = FMT_ALIGN_CENTER), FMT_KEY(bool, f, false, .pad = 9, .align = FMT_ALIGN_CENTER), FMT_KEY(bool, t, true, .pad = 9, .align = FMT_ALIGN_CENTER), FMT_KEY(CString, bar, "", .pad = 9, .padder = '-'), ); fmt_console( "Custom formatter example: '{}'\n" "\n", FMT(ptr, (&(IVec3) {42, -24, 123}), .fmt = fmt_ivec3), ); { char const *format = "{pill}Rendering{heart}to{heart}a{heart}string{heart}test{pill}\n" "\n"; FormatArg format_args[] = { FMT_KEY(CodePoint, pill, 0x1f48a), FMT_KEY(WideCString, heart, L"🩷"), }; isize required_string_size = fmt_string_write_impl(NULL, 0, format, format_args, ARRAY_SIZE(format_args)); u8 *string = FMT_ALLOC(required_string_size); fmt_string_write_impl( string, required_string_size, format, format_args, ARRAY_SIZE(format_args) ); fmt_console("{}", FMT(StringView, ((StringView) {string, required_string_size}))); FMT_DEALLOC(string); } return 0; }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree