473,381 Members | 1,493 Online

# Operator Precence Issue/Question

Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {
// Code
}

0x03==0x03 always equates to TRUE. Therefore my code equates to

if (P8 & TRUE) {
// code
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.

(I fully expect the answer to be "It depends on the compiler")

Thanks

Steven (who usually uses the strongly typed VHDL)

Jul 4 '06 #1
14 1823
mo****@yahoo.co.uk said:
Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}
Simplifying, without loss of generality: if(x & y == z)

Yes, it's a nasty one, that; dmr acknowledges that it was a mistake which
ought to have been fixed at an early stage. Too late now, of course.
>
There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {
Yes. More simply:

if(x & (y == z))
// Code
}

0x03==0x03 always equates to TRUE.
Well, it is either true or false. If it were false, it would yield 0. Since
it is true, it yields 1. (All conditional expressions behave in this way.)
Therefore my code equates to

if (P8 & TRUE) {
// code
More precisely, and using my generalisation:

if(x & 1)
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.
The statement that succeeds the if() will be executed if the low bit of your
first value is set - i.e. if(x & 1) evaluates to 1.
(I fully expect the answer to be "It depends on the compiler")
For a mercy, it actually doesn't depend on the compiler on this occasion!
The operators == != < <= = always yield either 0 or 1 as their result,
and that is guaranteed by the Standard:
6.5.8 [...] Each of the operators < (less than), (greater than),
<= (less than or equal to), and >= (greater than or equal
to) shall yield 1 if the specified relation is true and 0 if
it is false.80) The result has type int.

6.5.9 [...] Each of the operators yields 1 if the
specified relation is true and 0 if it is false. The result
has type int.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 4 '06 #2
Richard,

Thank you for the full and detailed response.

And as luck would have it, it's also the answer I wanted (by which I
mean I can work around without anyone knowing :-) )

Steven

Richard Heathfield wrote:
mo****@yahoo.co.uk said:
Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

Simplifying, without loss of generality: if(x & y == z)

Yes, it's a nasty one, that; dmr acknowledges that it was a mistake which
ought to have been fixed at an early stage. Too late now, of course.

There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {

Yes. More simply:

if(x & (y == z))
// Code
}

0x03==0x03 always equates to TRUE.

Well, it is either true or false. If it were false, it would yield 0. Since
it is true, it yields 1. (All conditional expressions behave in this way.)
Therefore my code equates to

if (P8 & TRUE) {
// code

More precisely, and using my generalisation:

if(x & 1)
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.

The statement that succeeds the if() will be executed if the low bit of your
first value is set - i.e. if(x & 1) evaluates to 1.
(I fully expect the answer to be "It depends on the compiler")

For a mercy, it actually doesn't depend on the compiler on this occasion!
The operators == != < <= = always yield either 0 or 1 as their result,
and that is guaranteed by the Standard:
6.5.8 [...] Each of the operators < (less than), (greater than),
<= (less than or equal to), and >= (greater than or equal
to) shall yield 1 if the specified relation is true and 0 if
it is false.80) The result has type int.

6.5.9 [...] Each of the operators yields 1 if the
specified relation is true and 0 if it is false. The result
has type int.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 4 '06 #3
mo****@yahoo.co.uk wrote:
Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}
What is uint8? Standard C has no such type, but has uint8_t.
There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {
// Code
}

0x03==0x03 always equates to TRUE. Therefore my code equates to

if (P8 & TRUE) {
// code
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.
In C, the relational operators always return 1 for true and 0 for
false, so in your case P8 would be bitwise and'ed with 0x01. So the IF
will evaluate to true if the Least Significant Bit of P8 is set, in
which case the statements inside the IF block will execute, otherwise
control will transfer to the statement after the IF block, (maybe an
ELSE?).
(I fully expect the answer to be "It depends on the compiler")
I don't know for sure, but I don't believe compilers will differ over
this. The Standard guarentees that relational expressions will yield
either 1 or 0, so conforming compilers, (compiling in a conforming
mode), should all behave the same.

Whether the IF evaluates true or not depends on the bit representation
of P8, (i.e. it's vaue), which only you know.

Jul 4 '06 #4
mo****@yahoo.co.uk wrote:
Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. [...]
Some compilers and some "lint" programs will issue
warnings for perfectly valid C that likely doesn't mean
what was intended. Check the documentation for your
compiler and/or lint to see whether you can make them
more sensitive to this sort of thing, so as to avoid such
errors in the future.

Even if you ultimately use Frobozz Magic C to compile
compilations with gcc, say, just for the diagnostics.

--
Eric Sosman
es*****@acm-dot-org.invalid
Jul 4 '06 #5

Eric Sosman wrote:
mo****@yahoo.co.uk wrote:
Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. [...]

Some compilers and some "lint" programs will issue
warnings for perfectly valid C that likely doesn't mean
what was intended.
.... snip ...

By saying there is a mistake in his code, the OP is talking about a
semantic error on his part, not that the code was rejected by the
compiler, (since as you say, it's perfectly valid C).

Jul 4 '06 #6
santosh wrote:
Eric Sosman wrote:
>>mo****@yahoo.co.uk wrote:
>>>Experts,

I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. [...]

Some compilers and some "lint" programs will issue
warnings for perfectly valid C that likely doesn't mean
what was intended.

... snip ...

By saying there is a mistake in his code, the OP is talking about a
semantic error on his part, not that the code was rejected by the
compiler, (since as you say, it's perfectly valid C).
Yes, and I'm also saying that some compilers will issue
warnings for "perfectly valid but quite possibly erroneous C."
Do you doubt this?

By encouraging his compilers and other tools to emit such
warnings and by paying attention to what they tell him, he
may be able to increase the likelihood that such semantic
errors will be caught before they become embarrassing.

--
Eric Sosman
es*****@acm-dot-org.invalid

Jul 4 '06 #7
Eric Sosman wrote:
santosh wrote:
Eric Sosman wrote:
>mo****@yahoo.co.uk wrote:
.... snip ...
>>There is a mistake in this code in that equality is higher precedence
than bitwise and. [...]

Some compilers and some "lint" programs will issue
warnings for perfectly valid C that likely doesn't mean
what was intended.
... snip ...

By saying there is a mistake in his code, the OP is talking about a
semantic error on his part, not that the code was rejected by the
compiler, (since as you say, it's perfectly valid C).

Yes, and I'm also saying that some compilers will issue
warnings for "perfectly valid but quite possibly erroneous C."
Do you doubt this?
No. I failed to grasp what you meant the first time around. I
understand now, though, in my limited experience, I've yet come across
a compiler that smart, but then again, I've only used about five
different compilers. I've found splint to be more suited for this.
By encouraging his compilers and other tools to emit such
warnings and by paying attention to what they tell him, he
may be able to increase the likelihood that such semantic
errors will be caught before they become embarrassing.
Absolutely, though these tools should not be a replacement for a C
textbook.

Jul 4 '06 #8
santosh wrote:
Eric Sosman wrote:
>>santosh wrote:
>>>By saying there is a mistake in his code, the OP is talking about a
semantic error on his part, not that the code was rejected by the
compiler, (since as you say, it's perfectly valid C).

Yes, and I'm also saying that some compilers will issue
warnings for "perfectly valid but quite possibly erroneous C."
Do you doubt this?

No. I failed to grasp what you meant the first time around. I
understand now, though, in my limited experience, I've yet come across
a compiler that smart, but then again, I've only used about five
different compilers. I've found splint to be more suited for this.
You should make a point of becoming acquainted with gcc.
Many things good and bad can be and have been said of it, but
IMHO it has the best diagnostics of any compiler I've encountered.
(If properly propitiated, of course: "-Wall -W -ansi -pedantic"
is a good starting point, possibly with "-std=something_else"

--
Eric Sosman
es*****@acm-dot-org.invalid
Jul 4 '06 #9
On 2006-07-04, Eric Sosman <es*****@acm-dot-org.invalidwrote:
santosh wrote:
>Eric Sosman wrote:
>>>santosh wrote:

By saying there is a mistake in his code, the OP is talking about a
semantic error on his part, not that the code was rejected by the
compiler, (since as you say, it's perfectly valid C).

Yes, and I'm also saying that some compilers will issue
warnings for "perfectly valid but quite possibly erroneous C."
Do you doubt this?

No. I failed to grasp what you meant the first time around. I
understand now, though, in my limited experience, I've yet come across
a compiler that smart, but then again, I've only used about five
different compilers. I've found splint to be more suited for this.

You should make a point of becoming acquainted with gcc.
Many things good and bad can be and have been said of it, but
IMHO it has the best diagnostics of any compiler I've encountered.
(If properly propitiated, of course: "-Wall -W -ansi -pedantic"
is a good starting point, possibly with "-std=something_else"
Agreed.

For example, I once used the construct (ch[1] == ch[2] == '-') to check
for a comment in an XML document (it was already known that ch[0] was '<').
I likely would have had a very difficult time noticing that bug on my own,
because the construct "a = b = c" /is/ correct. (This is an interesting
variant on the =/== typo that isn't mentioned in any books I've read).

Anyway, gcc gave me the following message (paraphrased):
warning: expressions of the form (a <= b <= c) do not have their
mathematical meaning.

and saved me several potential hours of debugging.

--
Andrew Poelstra <http://www.wpsoftware.net/blog>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 4 '06 #10
Eric Sosman wrote:
santosh wrote:
Eric Sosman wrote:
>santosh wrote:

By saying there is a mistake in his code, the OP is talking about a
semantic error on his part, not that the code was rejected by the
compiler, (since as you say, it's perfectly valid C).

Yes, and I'm also saying that some compilers will issue
warnings for "perfectly valid but quite possibly erroneous C."
Do you doubt this?
No. I failed to grasp what you meant the first time around. I
understand now, though, in my limited experience, I've yet come across
a compiler that smart, but then again, I've only used about five
different compilers. I've found splint to be more suited for this.

You should make a point of becoming acquainted with gcc.
Though gcc is what I use 90 % of the time, I haven't really explored
it's options in depth. I really should though.
Many things good and bad can be and have been said of it, but
IMHO it has the best diagnostics of any compiler I've encountered.
I agree and I would probably place Borland's compiler second in this
regard.
(If properly propitiated, of course: "-Wall -W -ansi -pedantic"
is a good starting point, possibly with "-std=something_else"
Exactly what I use for all my programs, (with std=c99 for the
ocassional one that needs it). Recently I've started trying the
exhaustive set of diagnostics switches Richard Heathfield posted. It's
made me reconsider quite a number of constructs, (plus the excellent
knowledge of this group of course).

Jul 4 '06 #11
Richard Heathfield <in*****@invalid.invalidwrites:
mo****@yahoo.co.uk said:
[...]
>0x03==0x03 always equates to TRUE.

Well, it is either true or false. If it were false, it would yield 0. Since
it is true, it yields 1. (All conditional expressions behave in this way.)
More precisely, all conditional *operators* behave in this way. The
language guarantees that the relational, equality, "&&", "||", and "!"
operators yield 1 for true and 0 for false. Other things that you
might think of as conditional expressions (e.g., a call to isdigit())
don't have this guarantee.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jul 4 '06 #12

mo****@yahoo.co.uk wrote:
I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {
// Code
}

0x03==0x03 always equates to TRUE. Therefore my code equates to

if (P8 & TRUE) {
// code
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.

(I fully expect the answer to be "It depends on the compiler")
Is following the lines of code what you want,

int l2bs(int i)
{
const unsigned char MASK = 0x03; /*0000 0011*/
i = 1; /*last 2 bits are set*/
else
i = 0; /*last 2 bits are not set*/
return i;
}

lovecreatesbeauty

Jul 5 '06 #13
All,

Thanks for the advice and observations.

I will certainly look into the pendantic warnings options within GCC to
try an catch this type bug in future.

Steven

lovecreatesbeauty wrote:
mo****@yahoo.co.uk wrote:
I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {
// Code
}

0x03==0x03 always equates to TRUE. Therefore my code equates to

if (P8 & TRUE) {
// code
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.

(I fully expect the answer to be "It depends on the compiler")

Is following the lines of code what you want,

int l2bs(int i)
{
const unsigned char MASK = 0x03; /*0000 0011*/
i = 1; /*last 2 bits are set*/
else
i = 0; /*last 2 bits are not set*/
return i;
}

lovecreatesbeauty
Jul 5 '06 #14
On 2006-07-05, lovecreatesbeauty <lo***************@gmail.comwrote:
>
mo****@yahoo.co.uk wrote:
>I have written (and delivered :-( ) some code. I wanted to check that
the bottom two bits of P8 were set, and so I produced:

if (P8 & (uint8)0x03 == (uint8)0x03) {
// Code
}

There is a mistake in this code in that equality is higher precedence
than bitwise and. Therefore my code behaves as:

if (P8 & ((uint8)0x03 == (uint8)0x03)) {
// Code
}

0x03==0x03 always equates to TRUE. Therefore my code equates to

if (P8 & TRUE) {
// code
}

So my question is, how is TRUE likely to be represented, and when will
the code be run.

(I fully expect the answer to be "It depends on the compiler")

Is following the lines of code what you want,

int l2bs(int i)
{
const unsigned char MASK = 0x03; /*0000 0011*/
i = 1; /*last 2 bits are set*/
else
i = 0; /*last 2 bits are not set*/
return i;
}
That function could be replaced with

int l2bs (int i)
{
return (i & 0x03) == 0x03
}

Or a macro:
#define #L2BS(n) ((n) & 3 == 3)

--
Andrew Poelstra <http://www.wpsoftware.net/projects/>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 5 '06 #15

This thread has been closed and replies have been disabled. Please start a new discussion.