Skip to content

Operators

SafeC supports the full set of C operators plus SafeC-specific extensions for overflow control. This page is a complete reference for all operators, their precedence, and associativity.

Arithmetic Operators

Binary Arithmetic

OperatorDescriptionExample
+Additiona + b
-Subtractiona - b
*Multiplicationa * b
/Divisiona / b
%Modulo (remainder)a % b

Unary Arithmetic

OperatorDescriptionExample
+xUnary plus (identity)+a
-xUnary negation-a

Increment and Decrement

OperatorDescriptionExample
++xPre-increment (increment, then return)++counter
x++Post-increment (return, then increment)counter++
--xPre-decrement (decrement, then return)--index
x--Post-decrement (return, then decrement)index--
c
int x = 5;
int a = ++x;   // x is 6, a is 6
int b = x++;   // b is 6, x is 7
int c = --x;   // x is 6, c is 6
int d = x--;   // d is 6, x is 5

Overflow-Aware Arithmetic

SafeC adds operator variants for explicit overflow control. See Overflow Operators for detailed usage.

OperatorDescriptionBehavior
+|Wrapping additionTwo's complement wrap
-|Wrapping subtractionTwo's complement wrap
*|Wrapping multiplicationTwo's complement wrap
+%Saturating additionClamp to min/max
-%Saturating subtractionClamp to min/max
*%Saturating multiplicationClamp to min/max

Assignment Operators

Simple Assignment

c
int x = 42;
x = 100;

Compound Assignment

Compound assignment operators combine an arithmetic or bitwise operation with assignment. a op= b is equivalent to a = a op b.

OperatorDescriptionEquivalent
+=Add and assigna = a + b
-=Subtract and assigna = a - b
*=Multiply and assigna = a * b
/=Divide and assigna = a / b
%=Modulo and assigna = a % b
&=Bitwise AND and assigna = a & b
|=Bitwise OR and assigna = a | b
^=Bitwise XOR and assigna = a ^ b
<<=Left shift and assigna = a << b
>>=Right shift and assigna = a >> b
c
int x = 10;
x += 5;     // x is 15
x -= 3;     // x is 12
x *= 2;     // x is 24
x /= 4;     // x is 6
x %= 5;     // x is 1

uint32 flags = 0xFF00;
flags &= 0x0F0F;    // flags is 0x0F00
flags |= 0x00F0;    // flags is 0x0FF0
flags ^= 0x0FF0;    // flags is 0x0000

Comparison Operators

OperatorDescriptionExample
==Equala == b
!=Not equala != b
<Less thana < b
>Greater thana > b
<=Less than or equala <= b
>=Greater than or equala >= b

All comparison operators return bool.

Logical Operators

OperatorDescriptionExample
&&Logical AND (short-circuit)a && b
||Logical OR (short-circuit)a || b
!Logical NOT!a

Short-circuit evaluation: && does not evaluate the right operand if the left is false; || does not evaluate the right operand if the left is true.

c
if (ptr != null && *ptr > 0) {
    // safe: *ptr is only evaluated if ptr is non-null
}

Bitwise Operators

OperatorDescriptionExample
&Bitwise ANDa & b
|Bitwise ORa | b
^Bitwise XORa ^ b
~Bitwise NOT (complement)~a
<<Left shifta << n
>>Right shifta >> n
c
uint32 flags = 0b1100;
uint32 mask  = 0b1010;

uint32 and_result = flags & mask;   // 0b1000
uint32 or_result  = flags | mask;   // 0b1110
uint32 xor_result = flags ^ mask;   // 0b0110
uint32 not_result = ~flags;         // all bits flipped

uint32 shifted = 1 << 4;           // 16 (bit 4 set)

Member Access Operators

OperatorDescriptionExample
.Value member accesspoint.x
->Pointer member accessptr->x
::Scope resolution / method definitionPoint::length()

The . operator accesses fields on values and references. The -> operator dereferences a pointer and accesses a field in one step.

c
struct Point { double x; double y; };

Point p = {3.0, 4.0};
double x1 = p.x;            // value access

Point *ptr = &p;
double x2 = ptr->x;         // pointer dereference + access
// equivalent to: (*ptr).x

The :: operator is used for method definitions and static scope resolution:

c
double Point::length() const {
    return sqrt_d(self.x * self.x + self.y * self.y);
}

Subscript Operator

Array and slice indexing uses []. Accesses are bounds-checked in safe contexts.

c
int arr[5] = {10, 20, 30, 40, 50};
int x = arr[2];              // 30 (bounds-checked)

[]int s = arr[1..4];
int y = s[0];                // 20 (bounds-checked via slice length)

Ternary Operator

The conditional (ternary) operator evaluates one of two expressions based on a condition:

c
condition ? then_expr : else_expr
c
int x = 10;
int y = 20;
int max = (x > y) ? x : y;       // max is 20

const char *label = (count == 1) ? "item" : "items";

The ternary operator has very low precedence — use parentheses around complex conditions for clarity.

Comma Operator

The comma operator evaluates the left operand, discards the result, then evaluates and returns the right operand:

c
int x = (a = 1, b = 2, a + b);   // x is 3

The most common use is in for loop headers:

c
for (int i = 0, j = 10; i < j; i++, j--) {
    // i counts up, j counts down
}

Address-of and Dereference

OperatorDescriptionExample
&Address-of (creates a region-qualified reference)&x
*Dereference (access value through pointer/reference)*ptr
c
int x = 42;
&stack int ref = &x;         // region-qualified reference
int y = *ref;                // dereference: y is 42

See Memory & Regions for region-qualified reference details.

OperatorDescriptionExample
(T)exprExplicit cast(double)x
sizeof(T)Size of a type in bytessizeof(int)
sizeof(expr)Size of an expression's type in bytessizeof(x)
alignof(T)Alignment requirement of a typealignof(double)
c
int x = 42;
double d = (double)x;        // explicit cast

long s1 = sizeof(int);       // 4
long s2 = sizeof(x);         // 4
long a = alignof(double);    // 8 (platform-dependent)

See Compile-Time Introspection for typeof, fieldcount, and sizeof....

Operator Precedence

From highest to lowest precedence:

PrecedenceOperatorsAssociativity
1 (highest)() [] . -> x++ x--Left-to-right
2++x --x +x -x ! ~ * & (T) sizeof alignofRight-to-left
3* / % *| *%Left-to-right
4+ - +| -| +% -%Left-to-right
5<< >>Left-to-right
6< <= > >=Left-to-right
7== !=Left-to-right
8&Left-to-right
9^Left-to-right
10|Left-to-right
11&&Left-to-right
12||Left-to-right
13? :Right-to-left
14= += -= *= /= %= &= ^= |= <<= >>=Right-to-left
15 (lowest),Left-to-right

Operator Overloading

Struct types can overload binary operators by defining methods named operator+, operator-, etc. See Functions for details.

Supported overloadable operators: +, -, *, /, %, ==, !=, <, >, <=, >=.

Released under the MIT License.