Operators#
C’s operator surface covers arithmetic, comparison, logical,
bitwise, pointer (& *), member access (. ->), array
indexing ([]), function call (()), sizeof, ? :,
the comma operator, and the assignment family. No operator
overloading; types decide what is legal.
For the values these act on, see Types.
Arithmetic#
Operator |
Meaning |
|---|---|
|
addition, subtraction, multiplication, division. Integer / integer truncates toward zero. |
|
modulo (integers only). Sign follows the dividend. |
|
increment / decrement. Prefix yields the new value; postfix yields the old. |
7 / 2 /* 3 (integer truncation) */
7.0 / 2 /* 3.5 (one operand is double) */
-7 % 3 /* -1 (sign of dividend) */
int i = 5;
int a = i++; /* a = 5, i = 6 */
int b = ++i; /* i = 7, b = 7 */
Relational#
1 == 1 /* 1 (true) */
"abc" == "abc" /* compares POINTERS, not bytes */
strcmp(s1, s2) == 0 /* the operator's actual string compare */
Pointer comparison compares addresses; the operator who wants
byte comparison uses memcmp (raw) or strcmp (null
terminated).
Logical#
&& and || short-circuit and return 0 or 1;
! is unary.
if (p != NULL && p->ready) { /* short-circuit avoids NULL deref */
use(p);
}
Bitwise#
Operator |
Meaning |
|---|---|
|
AND |
|
OR |
|
XOR |
|
bitwise NOT |
|
left shift |
|
right shift (sign-extending on signed, zero-fill on unsigned) |
uint32_t flags = 0;
flags |= READER; /* set */
flags &= ~READER; /* clear */
flags ^= READER; /* toggle */
if (flags & READER) { /* test */
/* … */
}
uint32_t hi = (val >> 16) & 0xffff;
uint32_t lo = val & 0xffff;
Right shift on a signed negative value is implementation-defined; the operator works on unsigned integers when shifting matters.
Assignment#
= plus the compound forms += -= *= /= %= &= |= ^= <<= >>=.
x = 1;
x += 2;
flags |= READER;
The result of an assignment is the assigned value, which is why
while ((c = getchar()) != EOF) works.
Pointer#
&xtakes the address ofx.*pdereferences (reads / writes through the pointer).p->fieldis(*p).field.
int x = 10;
int *p = &x;
*p = 20; /* x is now 20 */
struct user *u = malloc(sizeof *u);
u->name = "rk";
C has no managed pointers; every malloc pairs with a
free on every exit path.
Array / call#
a[i] is sugar for *(a + i); f(x) calls f.
xs[3] /* *(xs + 3) */
strlen("hello") /* 5 */
sizeof#
sizeof returns the size of a type or an expression in
size_t.
sizeof(int) /* compile-time constant */
sizeof xs /* total bytes of the array (NOT pointer size) */
sizeof *p /* size of the pointed-to type */
The classic mistake: sizeof an array parameter inside a
function gives the pointer size, not the array size, because
arrays decay.
Ternary#
cond ? a : b evaluates cond, then either a or
b; returns the chosen value.
int abs = (x < 0) ? -x : x;
const char *plural = (n == 1) ? "" : "s";
Comma#
The comma operator evaluates left then right, returning right.
Common only inside for headers.
for (int i = 0, j = 10; i < j; i++, j--) { /* … */ }
Precedence#
A subset, highest to lowest. The operator parenthesises anything ambiguous; the compiler does not warn.
Level |
Operator |
|---|---|
postfix |
|
postfix |
|
postfix |
|
postfix |
|
postfix |
|
postfix |
|
unary |
|
unary |
|
unary |
|
unary |
|
unary |
|
unary |
|
unary |
|
unary |
|
unary |
|
unary |
|
multiplicative |
|
multiplicative |
|
multiplicative |
|
additive |
|
additive |
|
shift |
|
shift |
|
relational |
|
relational |
|
relational |
|
relational |
|
equality |
|
equality |
|
bitwise |
|
bitwise |
|
bitwise |
|
logical |
|
logical |
|
ternary |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
assignment |
|
comma |
|
References#
Types for the values each operator accepts.
Control flow for how operators feed conditions and loops.
Functions for
sizeofof function parameters (the decay rule).