K
Keith Thompson
Please stop adding "Followup-To: Poster" to your article headers.
Please do check your jargon. I honestly can't understand what you're
trying to say.
None of the macro definitions for FALSE and TRUE have anything
to do with lvalues, nor is there any reason why they should.
(An lvalue is, more or less, an expression that designates an
object; all we have here are constants and constant expressions.)
And "to initialize a typedef" doesn't make any sense. What
exactly do you mean?
Huh?
Using an enum doesn't provide any type checking. Enum values can be
freely and implicitly converted to and from integer types. In fact,
enumeration constants are of type int, not of the enumerated type.
So don't do that. Why would you even consider it?
You can have macros that expand to constant expressions either
with or without a boolean type. In fact, that's exactly what C99's
<stdbool.h> does. "bool" is a macro that expands to "_Bool", which
is a predefined type. "false" and "true" are macros that expand
to 0 and 1, respectively, which are of type int. The implicit
conversions between int and _Bool mean that the differing types
aren't a problem unless you do something really strange (like
testing whether sizeof (bool) == sizeof true).
Ctalk Project said:Keith Thompson said:Ctalk Project said:<snip>
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.
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.
The definition of TRUE here is being used as an lvalue
label, not as a constant expression to initialize a typedef.
(Pardon me if I'm not checking the jargon against any
standards documents, I'm typing this as I go).
Please do check your jargon. I honestly can't understand what you're
trying to say.
None of the macro definitions for FALSE and TRUE have anything
to do with lvalues, nor is there any reason why they should.
(An lvalue is, more or less, an expression that designates an
object; all we have here are constants and constant expressions.)
And "to initialize a typedef" doesn't make any sense. What
exactly do you mean?
I'd add that due to the fact that anything "not 0" -> True,
the further example is still a little iffy, but "good
enough" for most cases. However, to use a compiler's
checking, a Boolean would have to be defined using an enum,
and that could be expensive.
Huh?
Using an enum doesn't provide any type checking. Enum values can be
freely and implicitly converted to and from integer types. In fact,
enumeration constants are of type int, not of the enumerated type.
I did think of an example, btw, when using a typedef'd
variable as an lvalue, instead of a constant. Then one
could say, for example, ++TRUE or --TRUE after the macro
expansion and the program could end up with a false True.
So don't do that. Why would you even consider it?
In fact, it might be better to do away with boolean types
entirely, and rely on macros that are constant expressions,
except that boolean types make source code so darn readable.
You can have macros that expand to constant expressions either
with or without a boolean type. In fact, that's exactly what C99's
<stdbool.h> does. "bool" is a macro that expands to "_Bool", which
is a predefined type. "false" and "true" are macros that expand
to 0 and 1, respectively, which are of type int. The implicit
conversions between int and _Bool mean that the differing types
aren't a problem unless you do something really strange (like
testing whether sizeof (bool) == sizeof true).