defining a boolean type

B

Beej Jorgensen

Ahh, but whether or not you asked about it, you should be aware that
doing stuff like that will make any future reader familiar with C
assume that your code is unreliable.

This is an absolutely valid warning, regardless of the actual
reliability of the code.
Why don't you go a bit further and write:

TRUE = (((1!=0)!=(1!=1))!=0)

Because, as I'm guessing you'd agree, (1==0) is clearly "false", while
(((1!=0)!=(1!=1))!=0) is clearly "insane". :)
If you are 100% sure that (1==0) is 0, just write 0.

All in the name of clarity, I say. If you found a situation where
saying (1==0) would clarify the code or improve its readability, I'll
bet you'd write it. I don't think the OP is in one of those situations,
though--"FALSE=0" has pretty unambiguous meaning.

But I've written things like "<<0" in code before where I thought it
improved clarity for future maintainers. Or I've left in unsimplified
constant arithmetic expressions where it would help explain the thinking
behind it.

And while I personally wouldn't define FALSE as (1==0) in my code, I
don't think it's nearly as dire a monstrosity as (((1!=0)!=(1!=1))!=0),
nor is it as bad as horribly misplaced squirrely braces at column 97 or
whatever.

But the OP should define FALSE as 0 for some or all of these reasons:

1) C clearly defines it that way
2) All C coders know it
3) Defining it as (1==0) doesn't particularly improve clarity
4) People might harshly judge his code

That really should be enough--it doesn't have to get into a weird
subjective style fight with extreme fabricated coding examples.

-Beej
 
H

Hamiral

James said:
In C, the repesentations of boolean truth and
falsity are 1 and 0. Always have been. Always
will be. A C programmer who doesn't know this as
well as he knows how to breathe is not a C programmer.

Strange, I always thought FALSE was 0 and TRUE was anything else...

Ham
 
K

Keith Thompson

Hamiral said:
Strange, I always thought FALSE was 0 and TRUE was anything else...

Anything other than 0 is true(adjective), but true(noun) is 1.

You can only define a single value as TRUE (or true). The most
obvious value to use is 1. It's the value yielded by the "!",
relational, equality, "&&", and "||" operators, and it's the value
used in C99's <stdbool.h>.

If it were possible to do something like:

#define false 0
#define true anything-other-than-0
typedef int bool;

and have (2 == true) be true, then that would be more consistent.

The only valid value for "false" is 0, and the only really sensible
value for "true" is 1. Just don't compare boolean values for
equality. For example, rather than

if (condition == true)

write

if (condition)
 
B

Ben Bacarisse

Ctalk Project said:
Probably not what the OP wanted, though what usually works for me is

#define FALSE 0
#define TRUE !(FALSE)

You probably meant (!FALSE). Examples where your definition of TRUE
don't work as expected are a little contrived but they do exist.

<snip>
 
S

Seebs

You probably meant (!FALSE). Examples where your definition of TRUE
don't work as expected are a little contrived but they do exist.

And I even looked at it without seeing it...

Which is the OTHER reason I hate these fancy attempts to calculate the
two most hard-coded values in the C language. This is the only thing I
actually think is worse than sizeof(char), which at least CAN have documentary
value when used to preserve parallels between related cases.

-s
 
N

Nick

Keith Thompson said:
Header inclusion is idempotent for the standard headers, *except* for
<assert.h>. See C99 7.1.2p1:

Standard headers may be included in any order; each may
be included more than once in a given scope, with no effect
different from being included only once, except that the effect
of including <assert.h> depends on the definition of NDEBUG
(see 7.2).

#including <assert.h> multiple times won't cause a collision.
C99 7.2p1:

The assert macro is redefined according to the current state of
NDEBUG each time that <assert.h> is included.

And, to state the obvious, it won't affect any 'assert's that have been
through the pre-processor (phase) but will affect that have still to be
seen. So part of your code can have 'assert's turned on, and part have
them turned off, without any problems.
 
N

Nick

Beej Jorgensen said:
But I've written things like "<<0" in code before where I thought it
improved clarity for future maintainers. Or I've left in unsimplified
constant arithmetic expressions where it would help explain the thinking
behind it.

24*60*60 and related expressions - leaving the expression in is better
than a comment explaining what 84600 is (even if half of you know
already).
 
N

Nick Keighley

whilst I strongly displike (1==0) I think you're going too far here. I
have known a programmer that was quite insistant on this usage and
otherwise wrote quite good C (though he was a bit of a manic
micro-"optimiser").

I've seen this a lot

#define FALSE 0
#define TRUE !FALSE

Very simple:

The C99 bool value false is 0.  Not "the value FALSE".  0.  So you should
be providing the SAME value or you'll have some weird drift between versions.

how? Both expressions evaluate to zero!


I suspect the (1==0) people think the expression isn't evaluated until
run time or something or aren't convinced that all C compilers for
ever and ever that true is 1 and false is 0.

I've seen this as well

/* shifted but */
#define BIT0 (1<<0)
#define BIT1 (1<<1)
#define BIT2 (1<<2)

I've never understood why this is better than a bunch of hex
constants. Hell *I'd* embed them in the code- or rather I'd use
sematically sensible macro names.

#define OUTER_DOOR_OPEN 0x0001
#define INNER_DOOR_OPEN 0x0002

void start_cycle (void)
{
clear_bit (INNER_DOOR_OPEN);
set_bit (OUTER_DOOR_OPEN);
}


Ahh, but whether or not you asked about it, you should be aware that
doing stuff like that will make any future reader familiar with C assume
that your code is unreliable.  

well not necessarily...

It's just plain wrong.  There is nothing
more-false-than-0 in C.

there's nothing more null pointer constant than 0 in C either but many
people use NULL.

Style matters.  In particular, given that you agree that it's mechanically
equivalent, why on earth are you specifying something in a more complicated
way rather than a simpler way?

arguably its clearer. gulp.
Why don't you go a bit further and write:

TRUE = (((1!=0)!=(1!=1))!=0)

?

I can't find it now but I used to have an expression like

#define TRUE (1 - 1 + 1)

that spelt out the words TRUE and FALSE in ASCII art. But sadly I
can't find it.
:-(
 
I

Ian Collins

Nick said:
I've seen this as well

/* shifted but */
#define BIT0 (1<<0)
#define BIT1 (1<<1)
#define BIT2 (1<<2)

I've never understood why this is better than a bunch of hex
constants. Hell *I'd* embed them in the code- or rather I'd use
sematically sensible macro names.

I've seen this:

#define BIT(n) (1<<n)
#define OUTER_DOOR_OPEN 0x0001
#define INNER_DOOR_OPEN 0x0002

followed by

#define OUTER_DOOR_OPEN BIT(0)
#define INNER_DOOR_OPEN BIT(1)

The use of the BIT() macro is handy in embedded systems where bits map
to I/O ports.
 
J

James Dow Allen

.
Strange, I always thought FALSE was 0 and TRUE was anything else...

Surely you didn't think implementations are at liberty to
assign any non-zero value to x in
x = 7 == 7;
:) :)

A good habit may be to prefix a "!!" to boolean values,
i.e. replace
is_red(FOO foo) /* is foo red ?*/
...
return answer;
with
...
return !!answer;

If you neglect this you may be burned when you do
if (is_red(apple) == TRUE)

The fact that such code, without the "!!", may fail
is just another reason to avoid any TRUE silliness.

Hope this helps.
James
 
N

Nick Keighley

Not in C.

And that's the thing -- we're not working in a pure void, we're working
in an existing language with established conventions and patterns.  And
in that language, since everyone knows what the boolean operators yield,
anyone who writes something like this is indirectly communicating that
they don't understand the boolean operators.

the same argument could be applied to TRUE and FALSE (or true and
false). Why not just cut out the middle man and use 1 and 0? There are
people who would (strongly) argue that. I think they are wrong but
there you go.

<snip>
 
S

Seebs

how? Both expressions evaluate to zero!

Sorry, I was trying to get at the distinction between "false" and "FALSE".
And I was confused.
there's nothing more null pointer constant than 0 in C either but many
people use NULL.

Well, yeah -- because I hope the compiler will have it cast to (void *) so
it actually gets noticed as a pointer.
that spelt out the words TRUE and FALSE in ASCII art.

Okay, *that's* a good reason.

-s
 
K

Keith Thompson

James Dow Allen said:
Surely you didn't think implementations are at liberty to
assign any non-zero value to x in
x = 7 == 7;
:) :)

A good habit may be to prefix a "!!" to boolean values,
i.e. replace
is_red(FOO foo) /* is foo red ?*/
...
return answer;
with
...
return !!answer;

If you neglect this you may be burned when you do
if (is_red(apple) == TRUE)

The fact that such code, without the "!!", may fail
is just another reason to avoid any TRUE silliness.

A much simpler solution is to avoid equality comparisons for boolean
values. Just write:

if (is_red(apple))

and it doesn't matter how TRUE is defined, or which true value is_red
returns.

Note that isdigit() and friends return arbitrary true values, not
necessarily 1.
 
T

TonyMc

Nick said:
24*60*60 and related expressions - leaving the expression in is better
than a comment explaining what 84600 is (even if half of you know
already).

You mean 86400. Not sure how that affects the validity of your argument.

Tony
 
N

Nick

TonyMc said:
You mean 86400. Not sure how that affects the validity of your argument.

Well if no-one had spotted it, it would have made my argument very
strongly - that putting the calculation in has several advantages
because you know what they mean, which you might skim past
#define SECONDS_IN_DAY 84600

It was an homage to Turing.
 
S

Seebs

the same argument could be applied to TRUE and FALSE (or true and
false). Why not just cut out the middle man and use 1 and 0? There are
people who would (strongly) argue that. I think they are wrong but
there you go.

I actually pretty much agree, but the convention of using the names "true"
and "false" is strong enough to be somewhat-justifiable. I guess. I'm
not totally sold on it.

I tend to use " = 0" and " = 1" when I want to set things to false or true
respectively, but I also freely use "any value that isn't 0" as a true value,
because sometimes that allows me to communicate both truth and data about
what specifically was true.

-s
 
F

Flash Gordon

Ctalk Project wrote:

Can you please not set the Follow-up to header to "Poster", it makes
replying to your post a pain. Always assuming it was not corrupted at my
end, that is!

though practically, the declarations need to be the following

typedef char Boolean;
#define True 1
#define False 0

for compatibility with Xlib definitions.

<snip>

No it shouldn't, since the OP was going for compatibility with
stdbool.h, so it should be true and false.

Also, in response to the suggestion of using an enum, although I would
have liked that method it is not compatible with stdbool.h since that
defines true and false as macros and explicitly allows then to be #undef'd

Similarly, for as close as you can get to compatibility with stdbool.h
the OP should be defining
typedef someintegertype _Bool
#define bool _Bool

Depending on usage you might want someintegertype to be (unsigned) int
or (unsigned) char.

Oh, and I know that _Bool is in the implementation name space, but we
are trying to get as close as possible to stdbool.h and if _Bool is
provided anyway you could always comment out (or conditionally define
out) the typedef.
 
K

Keith Thompson

[ignoring "Followup-To: Poster"]

Ctalk Project said:
Example please.... The parens should not be necessary at all
except that there might also be a contrived case where 0
expands to an expression.

And the ! operator has a higher precedence than &&, ||, ~,
<<, >>, and so forth with the other operators, so that
should rule out mis-evaluation because of grouping of
adjacent operators.

Quibble: ~ has the same precedence as !. But the indexing operator
binds more tightly than !.

Here's a highly contrived example:

#include <stdio.h>

#define FALSE 0
#ifdef DO_IT_RIGHT
#define TRUE (!FALSE)
#else
#define TRUE !(FALSE)
#endif

int main(void)
{
char c = TRUE["hello"];
printf("c = '%c' = %d\n", c, c);
return 0;
}

I find it much easier to cultivate the habit of *always*
parenthesizing each macro argument and the entire definition than
to figure out when it's not necessary. If nothing else, anyone
reading your code could waste substantial time verifying that
there's no problem. By contrast, if you wrote:

#define FALSE 0
#define TRUE (!FALSE)

it would be obvious to any knowledgable C programmer that there won't
be any precedence problems. (Parentheses around FALSE are unnecessary
since it's a single token, not a macro argument -- assuming that FALSE
was defined properly, as it was here.)

Of course this:

#define TRUE 1

is equivalent, simpler, and clearer.
 
B

Ben Bacarisse

Ctalk Project said:
Example please....

const char *names[] = { "false", "true" };
puts(TRUE[names]);

As I said... contrived.
The parens should not be necessary at all
except that there might also be a contrived case where 0
expands to an expression.

The () round FALSE and not needed, no. I don't see how 0 can expand
to anything.
And the ! operator has a higher precedence than &&, ||, ~,
<<, >>, and so forth with the other operators, so that
should rule out mis-evaluation because of grouping of
adjacent operators.

But postfix operators bind like [] bind tighter. The point being it
is almost always better just to bracket the result (as well as any
embedded arguments) than to try to reason about what is and is not
safe. I don't do it for integer literals, but that is because that
case is reasonably easy to reason about.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,233
Latest member
AlyssaCrai

Latest Threads

Top