why bother with operator precedence

Andrew P. Mullhaupt amull at Morgan.COM
Wed Mar 28 00:50:21 AEST 1990


I agree: there is no good reason to learn very much of the C precedence
table, and there are some good reasons not to. If you have to program
in more than one language on a daily basis, you just end up getting
annoyed at the idiomatic differences in expression evaluation, and you
end up skipping niceties like "do I need parentheses to separate boolean
clauses in a conditional?" and putting in parentheses because they are
universal. This might be coding for some kind of lowest common denominator
but anything else is exposed to some kind of risk. 

When you find someone else's code which relies on precedence to compress
many operations into one, you can pull apart the run-on expression
and form simple statements. Note: use of the 'short-circuit' booleans
and side-effects should be pulled apart into conditionals, or at least
formatted to reflect the flow of control. If you want to express a
multiple branch conditional you expect something like:

    if (C1) {
        S1;
    } else if (C2) {    /* separation of lines is used */
        S2;             /* to indicate flow of control */
        if (C3) {
            S3;
        }
    } else {
        S4;
    }

but when you have an assignment to a variable, you usually expect
something like:

    V =  Expression;    /* on one line if possible */

so when the two are combined (as some programmers often do in C)
what should the reader legitimately expect? You don't often see

    result = E1 || (fail_1_act, E2) || (fail_2_act, E3);

indented as:

    result = E1 ||
        (fail_1_act, E2) ||
            (fail_2_act, E3);

so unless you're out for the last drop of optimization you should use:

    if (E1) {                /* space is now available for */
        result = TRUE;       /* useful documentation */
    } else {
        fail_1_act;
        if (E2) {            /* for each branch */
            result = TRUE;
        } else {
            fail_2_act;
            result = E3;
        }
    }

and hope that your compiler knows enough to find common subexpressions
across the conditional statements. 

In the short-circuit boolean version, fail_1_act and fail_2_act are
likely to be evaluated for side effects. (What else is the role of
the comma operator?) Suppose that fail_1_act affects the value of the
expression E3. The effect of this action is more clearly expressed
in the last version.

Some might be tempted to use  "if (result=E1) ..." but there are some
unnecessary risks in this form. Replacing the "result = TRUE" statements
might convey an impression that code has been left out. 

I think this example points out how reliance on side effects and use
of precedence in the C language (which are common practices) lead to
unnecessary puzzles in reading C source. Some C programmers may know
enough to correctly practice minimal parenthesis code, but some other
programmers know enough not to bother with high-risk, low-reward code.

Later,
Andrew Mullhaupt

 



More information about the Comp.lang.c mailing list