Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ChrisA

macrumors G5
Original poster
Jan 5, 2006
12,581
1,697
Redondo Beach, California
I just fixed an obvious bug in a C program
Code:
if ( 'R' == name[0] != 'R')
I changed the above to read
Code:
if ( 'R' != name[0])

But the odd thing was that it worked differently depending on the platform it was compiled on. What does the ANSI C standard say? Could the gcc compiler have "optimized" this? I'm using various versions of gcc depending on the OS. I caught the bug on a Solaris 8 using gcc v3. Very odd that I should see different behavior on different platforms
 

TEG

macrumors 604
Jan 21, 2002
6,621
169
Langley, Washington
I just fixed an obvious bug in a C program
Code:
if ( 'R' == name[0] != 'R')
I changed the above to read
Code:
if ( 'R' != name[0])
But the odd thing was that it worked differently depending on the platform it was compiled on. What does the ANSI C standard say? Could the gcc compiler have "optimized" this? I'm using various versions of gcc depending on the OS. I caught the bug on a Solaris 8 using gcc v3. Very odd that I should see different behavior on different platforms

The code you changed it to is correct C (at least as I have ever learned). The other one looks like old-style C, but doesn't make any sense. It is not really platfrom specific, but compiler specific. GCC compiles things differently than CC, gcc fixed some problems, while breaking some 'tricks' that programmers used.

C in general is not Platform specific, the compilers are, and have to do things differently for different platforms. So some things work on one platform, because of the age of the compiler, others don't because it is not implemented yet in another compiler. Same thing happens with the JVM, something will work on one platform, but won't on another because it hasn't had that piece implemented yet (common for programs written for JAVA Unix, and trying to run on Mac JAVA or Windows JAVA, even though Windows Java is done by the same company).

TEG
 

ChrisA

macrumors G5
Original poster
Jan 5, 2006
12,581
1,697
Redondo Beach, California
The code you changed it to is correct C (at least as I have ever learned). The other one looks like old-style C, but doesn't make any sense.

No, not "old style C". X==Y!=Z is current valid ANSI syntax, but horrible style and should never be used. (it was a typographic error) But I thought for sure the result would be well defined by ANSI. I think it should be compiled as if written like (X==Y)!=Z Isn't the rule that if the operator president is equal then the expression is evaluated left to right?

Yes some things are different on diffract platforms. This software uses a GNU Autoconf script to look for that kind of stuff. But basic C language features one would think wold work the same.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Since != and == have the same precedence, we have to fall back to their associativity. In this case, it's right to left. So if we parenthesized your original statement it would be:
Code:
if ( 'R' == (name[0] != 'R') )

So first,
Code:
name[0] != R
would be evaluated. This would evaluate to 0 or 1 (sorry, I don't have the standard in front of me. I know for false it would be 0, and believe very strongly that true will evaluate to 1).

So next, either:
Code:
 'R' == 0
or
Code:
 'R' == 1

would be evaluated. This is where it gets tricky. The compiler will have to make an implicit cast as a char literal and the result of a boolean operator are not the same type. If 0 or 1 are cast to a char, then you are comparing:
Code:
 'R' == '\0'
or
Code:
 'R' == '\1'

This will always be false. However, if 'R' was cast to a "logical" (this isn't a type, but the compiler might be filling in some gaps for you) it is non-zero, so it would evaluate to true/logical 1. So then you would have:
Code:
 1 == 0
or
Code:
 1 == 1

So now this expression will evaluate to false/0 if name[0] != 'R' is false/0 or true/1 if name[0] != 'R' is true/1. In this situation, the statements would collapse to:
Code:
name[0] != 'R'

which is what you intended in the first place. Another option that I won't suss out completely is the compiler implicitly casting 'R' to an int, which would be 82. This compared to 0 or 1 would always be false just as if 0 or 1 were cast to a char.

Since I don't have the standard available I can't say which is "correct", but it may not be specified so this may be up to the interpretation of the compiler. The only time you would have gotten what you wanted was if, for logicals, the compiler tried to enforce != 0 strictly.

Such is the shortfall of a language without a boolean type.

Sorry this couldn't be more definitive, but hopefully it's at least somewhat enlightening in terms of the possibilities for the compiler's behavior. If you really want to see what gcc is doing, hand it a -S switch. I would try to isolate the offending code to make the resulting ASM easier to read.

-Lee
 

JVene

macrumors newbie
Jul 22, 2008
29
0
TEG is on point here.

My 2 cents.....

This looks like an edited fragment that really 'said' something else in some previous version, more like

if ( 'R' == name[0] && x[0] != 'R' ) ....

Of course, I'm inventing a proposed array x here to suggest there must have been something else on the mind of the writer at some point, where different tests were involved, and the '&& x[0]' was deleted without finishing through the second 'R'.

Now, the construct you have makes little sense to the compiler, because by the time 'it gets to' (we tend to anthropomorphize the machine don't we) the !=, the result of the first comparison (the ==) is a boolean, which can't promote to a value that correctly compares against an 'R'. That is, no result from the == test CAN compare to an 'R', so it will always be "!= 'R'" no matter how the first test came out - it will be true or false, comparing to a binary 0 or 1 in most compilers, but it could never be an 'R'.

There was a time when bool was not a 'formal' type in C. We often used some macro BOOL defined as an unsigned int or int, but it wasn't a 'built in' type. It has since become one, and so on different compilers the 'understanding' of the compiler differs. In all cases the result of the first == test is true or false, but if the built in type CAN'T be a bool, because the compiler is older and doesn't really 'think' in bools, it might not warn and the behavior might be errant.

On more recent compilers you will be warned, depending on your verbose settings, about the problem with the promotion. This can happen between compiler versions on the same platform (in line with TEG's point).

I bother to go this far to make a summary point. Portability is more important now than ever before. Whatever software we make, it is likely we'll have more customers if we consider portability when we write, and this kind of realization is exactly the stuff you have to think about when portability comes up - just what is common among the platforms and compilers, and which compilers should be choose to help portability.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.