Skip to main content
TinyCC implements comprehensive C language support, including full ANSI C, most of ISO C99, and many GNU C extensions. This makes TCC compatible with a wide range of existing C code while maintaining its small size and fast compilation speed.

ANSI C compliance

TCC implements all the ANSI C standard features:
  • Structure bit fields with full type support
  • Floating point numbers (long double, double, and float fully supported)
  • All standard data types and operations
  • Complete preprocessor implementation
TCC includes a full C preprocessor, so you can use all standard preprocessor directives including #include, #define, #ifdef, and conditional compilation.

ISO C99 extensions

TinyCC implements many features of the ISO C99 standard. Currently missing items are complex and imaginary numbers.

Supported ISO C99 features

VLAs allow you to declare arrays with runtime-determined sizes:
void process_data(int n) {
    int buffer[n];  // Size determined at runtime
    // ... use buffer
}
Full support for 64-bit integer types:
long long big_number = 0x123456789ABCDEFLL;
unsigned long long huge = 18446744073709551615ULL;
The _Bool type is supported for boolean values:
#include <stdbool.h>

bool is_valid = true;
if (is_valid) {
    // ...
}
__func__ is a string variable containing the current function name:
void debug_function() {
    printf("In function: %s\n", __func__);
}
__VA_ARGS__ can be used for function-like macros with variable arguments:
#define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)

dprintf(1, "Value: %d\n", 42);
dprintf(2, "Two values: %d, %s\n", 10, "test");

Additional C99 features

void example() {
    int x = 10;
    
    // Code here
    process(x);
    
    // Declaration can appear mid-block (like C++)
    int y = 20;
    process(y);
}
The inline and restrict keywords are recognized but currently ignored by TCC.

GNU C extensions

TCC implements many GNU C extensions for compatibility with GCC code.

Designator extensions

int a[10] = { [0] 1, [5] 2, 3, 4 };

Extended syntax

  • Escape character: \e is ASCII character 27 (ESC)
  • Case ranges: Use ranges in switch cases
switch(ch) {
case 'a' ... 'z':
    printf("lowercase\n");
    break;
case 'A' ... 'Z':
    printf("uppercase\n");
    break;
default:
    printf("other\n");
    break;
}

Attributes

The __attribute__ keyword allows specifying variable and function attributes:
// Align variable to 8 bytes
int a __attribute__ ((aligned(8), section(".mysection")));

// Force alignment to 1 byte
struct packed_data {
    char c;
    int i __attribute__ ((packed));
} __attribute__ ((packed));
int my_add(int a, int b) __attribute__ ((section(".mycodesection"))) 
{
    return a + b;
}
This generates the function in the specified assembly section.
// Standard C calling convention (default)
void func1(int x) __attribute__ ((cdecl));

// Pascal-like calling convention
void func2(int x) __attribute__ ((stdcall));

// Fast i386 calling convention (n = 1-3)
int func3(int a, int b, int c) __attribute__ ((regparm(3)));
For regparm(n), the first n parameters go in registers %eax, %edx, and %ecx.
  • unused: Suppress warnings for unused variables/functions
  • dllexport: Export function from DLL/executable (Windows)
  • nodecorate: Don’t apply decorations when exporting (Windows)

Advanced features

#define dprintf(fmt, args...) printf(fmt, ## args)

dprintf("no arg\n");
dprintf("one arg %d\n", 1);

Built-in functions

TCC supports several GCC built-in functions:
// Type compatibility check
if (__builtin_types_compatible_p(typeof(x), int)) {
    // x is an int
}

// Constant expression check
if (__builtin_constant_p(expr)) {
    // expr is a compile-time constant
}

Inline assembly

Full support for GCC-style inline assembly with a gas-like (GNU assembler) syntax:
static inline void * my_memcpy(void * to, const void * from, size_t n)
{
    int d0, d1, d2;
    __asm__ __volatile__(
        "rep ; movsl\n\t"
        "testb $2,%b4\n\t"
        "je 1f\n\t"
        "movsw\n"
        "1:\ttestb $1,%b4\n\t"
        "je 2f\n\t"
        "movsb\n"
        "2:"
        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
        : "memory");
    return to;
}
TCC includes its own x86 inline assembler with gas-like syntax. No intermediate files are generated, and GCC 3.x named operands are supported.

TinyCC-specific extensions

Predefined macros

  • __TINYC__: Defined to indicate TCC is being used
  • __TCC_BCHECK__: Defined when bounds checking is enabled (-b option)
  • __TCC_BACKTRACE__: Defined when backtrace support is enabled (-bt option)

Script support

#!/usr/local/bin/tcc -run
#include <stdio.h>

int main() 
{
    printf("Hello World\n");
    return 0;
}
#! at the start of a line is ignored to allow C scripting. Make the file executable with chmod +x and run it directly.

Binary literals

Binary digit literals are supported:
int mask = 0b10101010;  // Same as 0xAA or 170
int flags = 0b1111;     // Same as 15

Compatibility notes

__FUNCTION__ interpretation: TCC interprets __FUNCTION__ as C99 __func__ (a variable), not as a string literal like GCC does.

Pragma support

#pragma pack is supported for Windows compatibility:
#pragma pack(push, 1)
struct packed_struct {
    char c;
    int i;
};
#pragma pack(pop)

Standard version

Use -std=version to control __STDC_VERSION__:
  • -std=c11 or -std=gnu11: Sets to 201112
  • Otherwise: Sets to 199901

Build docs developers (and LLMs) love