Every operator in C has a priority and an associativity and you need to know both to be able to figure out what an expression evaluates to.

Another important idea in C is that assignment is treated as a dyadic operator with the lowest precedence. The operator = stores the value on the righthand side in the variable on the lefthand side and then its result is the value of the righthand side.

Put more academically you can say that the result of A=B is B but the operator has a side effect of storing the value of B in A.

In general side effects are bad ideas because they spoil the purity of the picture of an operation that combines a number of values to give a result.

For example, in A=B+C the + has a higher priority so B+C is evaluated and then the result is used in A=result.

Treating assignment as an operator means that you can, if you really want to, write expressions like

D=(A=B)+C

which first evaluates A=B to give B and as a side effect stores this in A and then adds C to B and assigns this to D.

Notice that == is the test for equality in C and so

A==(B=C)

assigns C to B and tests if C is equal to A in a single expression. The brackets are necessary because == has a higher priority than =.

Taking this a little further C also allows other operators to be combined with the assignment operator. For example,

A+=1

translates to A=A+1, because the + operator has a higher priority and so the righthand side of the equality evaluates to A+1.

Another subtle point concerns what

A*=2+3

evaluates to?

Is it (A*2)+3 or is it A*(2+3)?

The answer is that it is A*(2+3) even though the * should have a higher priority than the +.

Once you have introduced the idea of a side effect as part of the assignment operator you might as well carry on and introduce other operators with side effects.

For example, the unitary operator ++ when used as a postfix operator as in A++ returns current value of A, that it is the same as just writing A, but as a side effect it increments A. In other words if A is 3 then after B=A++, B is set to 3 and A is set to 4.

Notice that this is quite different from ++A, the corresponding unary prefix operator the result of which is A+1 and which has the side effect of incrementing A. That if A is 3 then after B=++A, B is set to 4 and so is A. Notice that the ++ postfix operator has the highest priority and associates from left to right and as a prefix operator it has a priority of 2 and associates from right to left. Also notice that A++ has the same meaning as A+=1.

It is this amazing richness of operators that makes C so attractive to anyone who has taken the time to master it. After a while you can write an expression such as

C += A++ + B++ + (D=++E) == F

I have to admit that it would take me time to work out exactly what this expression does and then I would quickly forget it!

This single line expression is equivalent to a number of lines of commands that don't make use of operators and whether this is good or bad depends on what your objectives are.

If you want to produce good easy to understand code that doesn't depend on subtle precedence and associativity rules then it is most definitely bad. Most C programmers wouldn't write something that looks like this but it is certainly within the capabilities of the language. I suppose you could say that in say Fortran or any mathematical language gives the number crunching programmer the ability to write expressions such as

A=B^D-C/E*D^+C-Z+24*G/S

but most would choose to break such a complex expression down into smaller, and hopefully meaningful sub-expressions.

Just because you have access to a dangerous weapon it doesn't mean you have to use it.

My final word is parentheses or brackets - use them whenever the precedence rules make the evaluation of an expression even slightly uncertain. Brackets are free, non-polluting and low in cholesterol.

If you want a practical example of their usefulness and a statement of the pattern to follow see Where did the logic go?

What are the limits to computation? The computer science theory of computation can be intimidating because of its use of logic but taking a programmer's approach makes it seem much simpler. So if you [ ... ]

Performing a computation sounds like a simple enough task and it is easy to suppose that everything is computable. In fact there are a range of different types of non-computability that we need to con [ ... ]