Expressions combine values in a type with the operations defined for the type, giving new values. A type gives both a set of values and operations on those values. The compiler must determine for each operation the type of the operands, so that it can translate to the proper code.
It is possible that different code is used for different types, even though the operation symbol is the same. For instance, "+" is used for both floating point and and integer add, even though the operations are very different. When a same-named operator is disambiguated through use of type information, the operator is said to be overloaded.
In deciding the type of the operands, the compiler might order a type conversion of one or both of the operands. This compiler-mandated type conversion is called a coercion. For instance, addition of shorts and addition of longs are not the same. An addition where one operand is a short and another a long has an simple intuitive meaning: as they are both numbers, add them as numbers, however the computer must be more explicit than that when choosing operations. Therefore it promotes, or coerces, the short to a long, and performs a long addition.
Many operators use a familiar infix notation, such as a + b. Other operators have surprising syntax. The notation has been chosen to make the reading of programs as natural as possible. Operators are prefix or postfix, and use a variety of symbols, often obscuring the regularity of the operator notation.
The minus sign is overloaded as an infix operator for subtraction, a-b, and as a prefix operator for negation of arithmetic sign, -a.
The type cast operator is a prefix operation which notation an type enclosed in parenthesis and preceding a value. The result of the operation is the value expressed in the new type.
The subscript operator is a postfix operator consisting of square brackets enclosing an expression yielding an integer value. For a variable of type "array of T", the operator yields a value of T. Example: int a[] ;, then a[2] is read: apply the [] operator to a, to yield the integer value that is stored in the third location of a.
The subscript operator can also yield an lvalue. On the left hand side of an expression, a[2] refers not to the value of the third location of the array a, but to the location itself.
The additional operator applied to a pointer must take mixed types: in p + a, p is a pointer and a is of integer type. The operator is commutative and it is legal, but uncommon, to write a + p as well. If p is type pointer to T, the result of p + a is as if p is of type array of T, and p + a is of type pointer to the element p[a]. This is formally correct only if p is in fact an array of T (as well as being a pointer to T), and a is either in the bounds of the array or one beyond the array in the positive direction.
In the expression a = 3, = is the assignment operator. In C, = is an operator, and not part of the syntax of an assignment statement, as is common in many languages. For instance a = b = 3, read as a = ( b = 3 ), is the application of the resulting value of the operation b = 3, which is 3, to the left hand side of the outer = operator. The operator is decidedly non-commutative: it is illegal to say 3 = a.
The function call syntax is an example of a postfix operator. If f(a), f is a function, and the () postfix operator causes the invocation of the function, after a recursive evaluation of all parameters inside the parenthesis.
The sizeof operator has the unusual syntax of a function call, however it is an operator, and sizeof is a keyword, not a function name.
The address-of operator (ampersand) and the indirection operator (star) are inverse prefix operators. The star operator can give an lvalue, but the address-of operator cannot be an lvalue. Hence *&a = 3 is a weird say of saying a = 3. It is tempting to think of indirection of as changing of a value. If p is of type pointer to T, then *p is of type T, as an rvalue (or the location to store a T, as an lvalue).