Skip to content

Overflow Operators

Integer overflow is a common source of bugs and security vulnerabilities in C. SafeC provides explicit overflow control through dedicated operator variants, giving the programmer full control over overflow behavior.

Default Behavior

By default, SafeC follows C semantics for compatibility:

  • Signed integers: overflow is undefined behavior (the compiler may optimize assuming it never happens)
  • Unsigned integers: overflow wraps around (modular arithmetic)
c
int x = 2147483647;           // INT_MAX
x = x + 1;                    // undefined behavior (signed overflow)

uint32 y = 4294967295;        // UINT32_MAX
y = y + 1;                    // wraps to 0 (defined behavior)

Wrapping Operators

Wrapping operators guarantee modular arithmetic for both signed and unsigned types. The result wraps around on overflow, using two's complement.

OperatorDescription
+|Wrapping addition
-|Wrapping subtraction
*|Wrapping multiplication

Examples

c
int x = 2147483647;           // INT_MAX (2^31 - 1)
int y = x +| 1;               // -2147483648 (wraps to INT_MIN)
int z = x +| x;               // -2 (wraps around)

uint8 a = 255;
uint8 b = a +| 1;             // 0 (wraps around)

int big = 1000000;
int overflow = big *| big;     // wraps (1000000^2 mod 2^32)

Use Cases

  • Hash functions and checksums
  • Sequence number arithmetic
  • Cryptographic operations
  • Ring buffer index calculations
c
// Ring buffer with wrapping index
uint32 write_idx = 0;
uint32 read_idx = 0;
const uint32 BUF_SIZE = 1024;

void push(int value) {
    buffer[write_idx % BUF_SIZE] = value;
    write_idx = write_idx +| 1;   // wraps safely at UINT32_MAX
}

Saturating Operators

Saturating operators clamp the result to the type's minimum or maximum value on overflow, instead of wrapping.

OperatorDescription
+%Saturating addition
-%Saturating subtraction
*%Saturating multiplication

Examples

c
int x = 2147483647;           // INT_MAX
int y = x +% 1;               // 2147483647 (saturates at INT_MAX)
int z = x +% 100;             // 2147483647 (still INT_MAX)

int a = -2147483648;          // INT_MIN
int b = a -% 1;               // -2147483648 (saturates at INT_MIN)

uint8 c = 250;
uint8 d = c +% 10;            // 255 (saturates at UINT8_MAX)
uint8 e = 5;
uint8 f = e -% 10;            // 0 (saturates at 0 for unsigned)

Use Cases

  • Audio and signal processing (clipping)
  • Color value calculations (clamped to 0-255)
  • Sensor readings with physical limits
  • Any domain where "closest representable value" is more useful than wrapping
c
// Audio sample mixing with saturation
int16 mix_samples(int16 a, int16 b) {
    return a +% b;             // clamps to [-32768, 32767]
}

// Color brightness adjustment
uint8 brighten(uint8 color, uint8 amount) {
    return color +% amount;    // clamps to 255, no wrap to dark
}

// Distance calculation that can't go negative
uint32 safe_distance(uint32 a, uint32 b) {
    if (a > b) return a -% b;
    return b -% a;
}

Comparison with Other Languages

LanguageDefaultWrappingSaturating
CUB (signed) / wrap (unsigned)N/AN/A
SafeCUB (signed) / wrap (unsigned)+| -| *|+% -% *%
RustPanic (debug) / wrap (release).wrapping_add().saturating_add()
ZigUndefined (optimized)+%@addWithOverflow
SwiftTrap&+clamping:

SafeC uses operator syntax rather than method calls, keeping expressions readable:

c
// SafeC: natural operator syntax
int result = a +| b *| c;

// vs. method-based (other languages)
// int result = a.wrapping_add(b.wrapping_mul(c));

Summary

CategoryOperatorsOverflow Behavior
Default+ - *UB for signed, wrap for unsigned
Wrapping+| -| *|Two's complement wrap for all types
Saturating+% -% *%Clamp to min/max of type

Released under the MIT License.