Hacker News new | ask | show | jobs
by Silhouette 4674 days ago
Most, if not all, of the problems people are describing in this discussion come down to trying to assign something that isn't a boolean value to a variable of boolean type, and expecting it to do something sensible. I don't see how this is ever going to have a happy ending.

If you had written

    bool a = (someInt & 0x02) == 0x02
or something similarly clear and unambiguous, nothing odd would happen, even in C.

(Edit: OK, that's not strictly true, because of the operator precedence order. It's never made sense to me that integer arithmetic operators have higher precedence than comparisons but bitwise logical operators have lower precedence, so if you remove the parentheses above then the resulting code doesn't do what you'd expect. I suppose this is because I'm looking at the problem as if comparison operators return a proper boolean value rather than an integer, and the ordering we've wound up with in C dates from a historical oddity about 40 years ago.)

The underlying problem with booleans in C99, as Linus and others have been saying, is that the language doesn't actually enforce basic type safety, so cases like your first example

    bool a = someInt & 0x02
that should result in a type error are allowed through, and with odd results: how does it make any sense for a boolean variable to have an integer value like 0x01 or 0x02?

Then programmers who relied on such odd results wind up writing horrific code like your second example

    bool a = !!(someInt & 0x02)
where fudge factors build on top of distortions to make the old hacks work.

And then we wonder why in 2013 we still have widely used, essential software that is riddled with security flaws and crash bugs. :-(

3 comments

The reason that & and | have lower precedence than the comparison operators is indeed historical - it's because the earliest versions of the language didn't have the logical boolean operators && and ||, so the bitwise & and | operators stood in for them. The lower precedence meant that you could write:

  if (x == 1 & y == 2) {
..and have it do what you meant. This became a bit of a wart when the && and || operators were introduced (still well before ANSI standardisation), but it was considered that changing it would have broken too much existing code.

    bool a = someInt & 0x02;
is perfectly fine in C99. 0 converts to false, non-zero converts to 1 when assigning to a _Bool.

What's not fine is people creating their own compatibility booleans where they define true as 1, as that would indeed break(rather odd..) code such as

    bool a = someInt & 0x02;
    if (a == true) 
If the bool above is not the C99 _Bool, but just a typedef to another integer type, you end up with if(0x02 == 1) evaluating to false.
> Then programmers who relied on such odd results wind up writing horrific code like your second example

What's horrific about that? Would it be better if we had:

    #define to_bool(_X) !!(_X)
    ...
    bool a = to_bool(someInt & 0x02);