Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Operator Precedence

52 views
Skip to first unread message

Lawrence D'Oliveiro

unread,
Feb 5, 2024, 8:24:59 PMFeb 5
to
Operator precedence in C, particularly in regard to the bitwise operators,
can be a bit awkward. Consider an expression like

(val & check_bits) == set_bits

which uses “check_bits” to mask out the bits to check from “val”, and then
compares the result to “set_bits”. A more natural precedence order would
allow this to be written without the parentheses:

val & check_bits == set_bits

I discovered a few years ago (quite by accident) that Python does make a
small change to the operator precedences to allow exactly this sort of
thing.

My question is, if this corresponding operator precedence change were to
be made in C, is there any actual real-world code that would break?

Malcolm McLean

unread,
Feb 5, 2024, 8:38:09 PMFeb 5
to
Yes tons of it. Badly written code because in any sensible coding
standard you must have the parentheses. But lots of code like that is
written because it works and, hey, you assume your reader knows C.

It's a bit hard to produce an example at the drop of a hat on demand,
but I read alot of C code and you do come across this sort of thing all
of the time.
--
Check out Basic Algorithms and my other books:
https://www.lulu.com/spotlight/bgy1mm

Kaz Kylheku

unread,
Feb 5, 2024, 9:02:16 PMFeb 5
to
On 2024-02-06, Lawrence D'Oliveiro <l...@nz.invalid> wrote:
> Operator precedence in C, particularly in regard to the bitwise operators,
> can be a bit awkward. Consider an expression like
>
> (val & check_bits) == set_bits

Yes, this is famous. It's because the bitwise & was used for combining
Boolean conditions, before && was introduced:

if (foo > 0 & odd(bar)) { ... }

In a 1982 e-mail, Dennis Ritchie wrote:

"In retrospect it would have been better to go ahead and change the
precedence of & to higher than ==, but it seemed safer just to split &
and && without moving & past an existing operator. (After all, we had
several hundred kilobytes of source code, and maybe 3 installations....)"

That's it. 600 kilobytes of code being preserved is why we can't have

val & check_bits == set_bits

and whatnot.

> My question is, if this corresponding operator precedence change were to
> be made in C, is there any actual real-world code that would break?

Yes; anything that does

some_condition & variable == TEST_VALUE

where && could have been used, but wasn't. Perhaps due to a typo;
but the code is tested and works since some_condition has the values
0 and 1.

A good time to fix it was when Dennis Ritchie and gang had 600 kilobytes
of code in 3 installations.

Yet, I think the situation could be repaired with a carefully
rolled-out plan.

Firstly, require all ambiguous uses of & to be parenthesized, so
that code like condition & variable == TEST_VALUE requires a diagnostic;
it has to be condition & (variable == TEST_VALUE) or
(condition & variable) == TEST_VALUE.

Then after a long period of obsolescence, remove the requirement for
parentheses, and introduce the new precedence for & and |.

By the time the obsolescence period is over, most old code still in use
would have been fixed to have the required parentheses. Those are now
optional; new code can start using the nicer new precedence.

Then any remaining broken old code can still be supported with old
dialect modes, like "gcc -std=c17" or lower.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazi...@mstdn.ca

Lawrence D'Oliveiro

unread,
Feb 5, 2024, 9:26:50 PMFeb 5
to
On Tue, 6 Feb 2024 01:37:54 +0000, Malcolm McLean wrote:

> On 06/02/2024 01:24, Lawrence D'Oliveiro wrote:
>
>> My question is, if this corresponding operator precedence change were
to
>> be made in C, is there any actual real-world code that would break?
>
> Yes tons of it. Badly written code because in any sensible coding
> standard you must have the parentheses.

Given that everybody has to write it with the parentheses in existing
code, changing the operator precedence will not affect the correctness of
such expressions.

Keith Thompson

unread,
Feb 5, 2024, 9:34:12 PMFeb 5
to
But not everyone does write it with the parentheses. Taking advantage
of some of the more arcane precedence rules might be uncommon, but it
does happen.

If there were a decision to change the precedence rules in some future
standard, compilers could start warning about code whose meaning would
change in the transition. (Alas, it's far too common to ignore warnings.)

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Medtronic
void Void(void) { Void(); } /* The recursive call of the void */

Lawrence D'Oliveiro

unread,
Feb 5, 2024, 9:54:45 PMFeb 5
to
On Mon, 05 Feb 2024 18:33:56 -0800, Keith Thompson wrote:

> But not everyone does write it with the parentheses.

Let us be clear about what we are talking about. You are suggesting that
people write an expression like

a «bitop» b «cmp» c

with the expectation that it means

a «bitop» (b «cmp» c)

because currently in C, anybody who wants it to mean

(a «bitop» b) «cmp» c

has to write it that way, with explicit parentheses, anyway.

The question is, who would write something like (with or without
parentheses)

a «bitop» (b «cmp» c)

and why? Because a comparison in C only returns either 0 or 1, while bit
operators are most useful dealing with multibit masks.

Kaz Kylheku

unread,
Feb 5, 2024, 9:59:04 PMFeb 5
to
On 2024-02-06, Lawrence D'Oliveiro <l...@nz.invalid> wrote:
> On Mon, 05 Feb 2024 18:33:56 -0800, Keith Thompson wrote:
>
>> But not everyone does write it with the parentheses.
>
> Let us be clear about what we are talking about. You are suggesting that
> people write an expression like
>
> a «bitop» b «cmp» c
>
> with the expectation that it means
>
> a «bitop» (b «cmp» c)

The problem is that this is what it means that regardless of anyone's
expectation.

> The question is, who would write something like (with or without
> parentheses)
>
> a «bitop» (b «cmp» c)

For one thing, someone who writes & instead of &&, or | instead of ||,
as a pure typo, and the operands happen to be in the {0, 1} domain so
that it works fine.

Lew Pitcher

unread,
Feb 5, 2024, 10:01:33 PMFeb 5
to
Given that
>>> v_a & v_b == v_c
is a valid expression that binary ANDs v_a with the truth value of the
expression (v_b == v_c), your proposed change in operator precedence would
greatly affect the correctness of the expression.

--
Lew Pitcher
"In Skills We Trust"

Lawrence D'Oliveiro

unread,
Feb 5, 2024, 10:05:54 PMFeb 5
to
On Tue, 6 Feb 2024 03:01:18 -0000 (UTC), Lew Pitcher wrote:

> Given that
>>>> v_a & v_b == v_c
> is a valid expression that binary ANDs v_a with the truth value of the
> expression (v_b == v_c), your proposed change in operator precedence
> would greatly affect the correctness of the expression.

That’s why I asked for “real-world” examples. Why would anyone want to
write such an expression with the bitwise operators, instead of using the
boolean ones?

Lew Pitcher

unread,
Feb 5, 2024, 11:49:10 PMFeb 5
to
On Tue, 06 Feb 2024 03:05:40 +0000, Lawrence D'Oliveiro wrote:

> On Tue, 6 Feb 2024 03:01:18 -0000 (UTC), Lew Pitcher wrote:
>
>> Given that
>>>>> v_a & v_b == v_c
>> is a valid expression that binary ANDs v_a with the truth value of the
>> expression (v_b == v_c), your proposed change in operator precedence
>> would greatly affect the correctness of the expression.
>
> That’s why I asked for “real-world” examples.

While I have no "real world" examples to give you, I have no doubt
that, somewhere in the hundreds of millions of lines of C code currently
in use, there are examples of exactly this sort of code.

> Why would anyone want to
> write such an expression with the bitwise operators, instead of using the
> boolean ones?

Because they can?
Because it suits their needs?
Because they don't know better?

It doesn't matter. The C standard has, up until now, permitted such code,
and so, somewhere, someone has written it. And, now, despite your preferences,
it must be maintained.

Tim Rentsch

unread,
Feb 6, 2024, 2:19:24 AMFeb 6
to
Lawrence D'Oliveiro <l...@nz.invalid> writes:

> Operator precedence in C, particularly in regard to the bitwise operators,
> can be a bit awkward. Consider an expression like
>
> (val & check_bits) == set_bits
>
> which uses ?check_bits? to mask out the bits to check from ?val?, and then
> compares the result to ?set_bits?. A more natural precedence order would
> allow this to be written without the parentheses:
>
> val & check_bits == set_bits
>
> I discovered a few years ago (quite by accident) that Python does make a
> small change to the operator precedences to allow exactly this sort of
> thing.
>
> My question is, if this corresponding operator precedence change were to
> be made in C, is there any actual real-world code that would break?

Surely the answer to that question is an emphatic yes, but in any
case it's the wrong question.

An obvious first question is, if such a change were made to C
(via changes to the ISO C standard), would it result an any
significant gain? The answer to that question is No. Some
things would be easier, some things would be harder, the overall
effect on programming effort might be a net positive, but it is
as best a second-order effect: possibly a gain, but not a
significant gain.

An obvious next question is, if such a change were made to C, how
much collateral damage would result? The answer to that question
is hard to know exactly, but without doubt it is at least huge.
Consider what happened with C99. For the most part C99 was upward
compatible with C90, with two exceptions: removal of implicit
function declarations, and removal of implicit int. Furthermore
those changes would cause diagnostics if run on C90 code that
didn't fit the C99 rules. Despite that it took a very long time,
probably at least a decade, before C99 was fully embraced by the
C community. The effect of a change in precedence relationships
surely would be much, much longer. An important principle in the
evolution of C is that working code keeps working. There are some
exceptions to that principle, but they are rare and modest in
scale. The proposed precedence change would not be an evolution
of the language but a bifurcation of the language. In this case
the "cure" is worse than the disease.

David Brown

unread,
Feb 6, 2024, 4:59:26 AMFeb 6
to
It's common to use && than & :

x == 1 && y == 2

People might use & rather than && because they want to avoid
short-circuit evaluation, or because they think (usually wrongly, but
sometimes people have to use weaker compilers) that it gives more
efficient code. They may also write things like :

if (x == true & y == true) ...

I'm struggling to find an example where this kind of thing would be
objectively good code, but people do write odd code. So yes, I think a
change in the precedence /would/ cause breakage, but not a lot, and
mostly in code that was a bit odd to start with. However, that's enough
to put it out of the question for a change to C.


0 new messages