Re: if (a & X || b & ~Y) in dasd.c

Peter T. Breuer (ptb@it.uc3m.es)
Mon, 19 Nov 2001 20:38:46 +0100 (MET)


"bill davidsen wrote:"
> If the code does what I think it does, it works as written. However, I
> usually would throw in parenthesis on something like this to be sure
> that the next person reading the code won't waste time thinking about

Which is WHY you do not put in parentheses.

C is designed with precedences that make sense. You can write
conditions the way they ought to be written, without parentheses.

a && b || c && d

is read exactly the same way as you would read

a * b + c * d

and I have no idea why people would think otherwise. && is the logical
multiplicative operator (1*x = x, x*0 = 0, x*y = y*x, x*(y*z) = (x*y)*z),
and || is the logical addition operator (x+0 = x, x+y = y +x,
x+(y+z)=(x+y)+z)) and they distribute correctly (x*(y+z) = (x*y)+(x*z)),
so why should you treat them as though they were some strange thing
from mars that needs parentheses?

> it. I always thought that good code was literature, which could be read,
> understood, and enjoyed by many.

Exactly so. So don't put in extra punctuation to help people that can't
read or you'll spoil it for us. Parentheses make things illegible, as
surely as ((2)=(((1))+((1)))) :-). If an expression is difficult for
you, don't write it!

Additive operators in C have weaker priority than multiplicative
operators at the same level. = is weaker than anything. Relational
operators are next weakest. Then bitwise operators. Then logical
operators. Then arithmetic operators, then monary operators, which are
strongest of all.

That's the natural way. It means you can write, instead of

*x++ += (((a+2) << 2) > (b-4));

*x++ += a+2 << 2 > b-4;

(but that's illegible simply by virtue of having too complicated a RHS
in either case), or

x = a & b || c & d;

because the & binds more tightly than || by virtue of being
bitwise, not logical. If you were to write

x = a & b | c & d;

that would also be right, because & binds more tightly by virtue of
being multiplicative.

x = a && b || c && d

is also right, for the same reason. All have the same logical
semantics, two have the same bitwise semantics. Two have the
same arithmetic semantics, I think ... obviously you can also add

x = a * b + c * d

to the list, and more variants - though you wouldn't want to.

Where you might get caught out is by not realizing that << is
weaker than arithmetic ops, so

*x++ += a+2 << 2 > b-4;

(what I wrote before) is NOT

*x++ += a + 2<<2 > b-4;

nor

*x++ += a+2 << 2 > b-4

nor

*x++ += a + 2 << 2>b - 4

Blech. I can't think of any more eccentric interpretations. The
principle is that the higher level and more additive an operator is,
the weaker it is. This is intuitive. You only need to parenthise
weak operators when you want them to be evaluated before a strong
operator acts. Thus

*x++ += *((x | 0x01) + (1<<*x))

to be silly. The commonest mistake is writing

x = y << z + w

instead of

x = y << (z++w)

But compare

x = y ** z + w

(should the power operator exist) and you'll see why it's wrong. << is
precisely a power operator, and not treating it as such is the error.

Peter
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/