[comp.lang.c] Defining TRUE and FALSE

jyegiguere@watmath.UUCP (07/08/87)

There's been a debate raging on the nets lately about what is a
"proper" definition for the TRUE and FALSE macros in C. 
The way we define these at the Computer Systems Group here at
UW (which we include in the <stdio.h> file for Waterloo C)
is:

          #define TRUE   ( 0 == 0 )
          #define FALSE  ( 1 == 0 )

The point here is that instead of letting the program arbitrarily
decide what TRUE and FALSE should be, we let the compiler decide,
which adds to the portability.  Since the above definitions are simple
constant expressions, any compiler worth its salt should recognize
them as such and not generate any less efficient code than a direct
comparison to a straight integer constant.

In actual effect, the definition for FALSE above could just as well
be replaced with

          #define FALSE   0

since in C only non-zero values are considered to be 'true' in
logical expressions.  People have noted that some programmers code
things like

          if( my_func() == TRUE )

when my_func() returns a non-zero value that isn't necessarily the 
same as TRUE.  In such cases why not code

          if( my_func() != FALSE )

since anyone who declares FALSE to be anything other than zero is
going to run into a few problems.  I still prefer the TRUE form
if I know for SURE that the function will return either TRUE or FALSE
as defined in <stdio.h>.  In any case, I find both forms above more
readable than 

          if( my_func() )

or

          if( !my_func() )

This, however, is due to personal preferences and I don't believe 
that one form is right and the other wrong (as long as they both
do the exact same thing!)

-----------------------------

Eric Giguere
Computer Systems Group, UW
 
Disclaimer:  The above views are NOT intended to represent those of
either the Computer Systems Group or the University of Waterloo.
 

ado@elsie.UUCP (07/09/87)

In article <13851@watmath.UUCP>, jyegiguere@watmath.UUCP (Eric Giguere) writes:

> The way we define these at the Computer Systems Group here at UW
> (which we include in the <stdio.h> file for Waterloo C)
> is:
> 
>           #define TRUE   ( 0 == 0 )
>           #define FALSE  ( 1 == 0 )

I used to do this (well, actually,
	#define FALSE (!TRUE)
is what I'd use), but code such as

			#define TRUE	(0 == 0)
			#define FALSE	(0 != 0)

			main()
			{
				int	i;

				i = TRUE;
				return i;
			}

gets flagged if you use lint's "-h" option:

			try.c(8): warning: constant in conditional context

To keep lint quiet, I've reverted to

			#define TRUE	1
			#define FALSE	0
-- 
	UUCP: ..seismo!elsie!ado	  ARPA: elsie!ado@seismo.CSS.GOV
	     Elsie and Ado are trademarks of Borden, Inc. and Ampex.

alyce@itsgw.UUCP (07/09/87)

For years I worked on projects that defined
	typedef enum {FALSE, TRUE} bool;
in a project-wide header file.  FALSE & TRUE were only used (by most
programmers) in assignments;  "if (first_time)" and "if ( !found )"
were the style used for comparisons.  We could define variables and
functions to be of type bool, and we always had this dream that 
someday we would have a version of lint that would warn against
setting or comparing bool variables to non-bool values.  Even now
that I'm back in school, where standards & conventions are unheard
of, I still use the bool type because I find it useful, readable,
& maintainable.

guy%gorodish@Sun.COM (Guy Harris) (07/09/87)

>           #define TRUE   ( 0 == 0 )
>           #define FALSE  ( 1 == 0 )

Which can be replaced by

	#define	TRUE	1
	#define	FALSE	0

in any C implementation that isn't horribly broken.  From K&R, page 189:

	7.6 Relational operators

	   ...

	The operators < (less than), ..., all yield 0 if the specified
	relation is false and 1 if it is true. ...

	7.7 Equality operators

	   ...

	The == (equal to) and the != (not equal to) operators are
	exactly analogous to the relational operators except for
	their lower precedence.  (Thus a<b == c<d is 1 whenever a<b
	and c<d have the same truth value.)

The ANSI C draft says much the same thing.  Unless substantial
evidence indicates otherwise, I assume that any compiler I deal with
will at least get the basics of C right (if a compiler I use doesn't,
I'll tell its maintainer ASAP, and possibly look at the problem
myself).  Even if there are such compilers, if I don't have to deal
with them I will write my code as if I could use standard C safely,
because I don't want to encourage screwups like that; if I have to
work around a compiler bug, I'll flag the code in question as being a
workaround.

> People have noted that some programmers code things like
> 
>           if( my_func() == TRUE )
> 
> when my_func() returns a non-zero value that isn't necessarily the 
> same as TRUE.  In such cases why not code
> 
>           if( my_func() != FALSE )
> 
> since anyone who declares FALSE to be anything other than zero is
> going to run into a few problems.

I presume that in this case "my_func()" returns something to be
thought of as a Boolean, except that any non-zero value, not just 1,
maps to TRUE.  If the function doesn't return a value that is a
Boolean (since C doesn't permit you to explicitly say that something
is Boolean, this means that it is not intended to be thought of as
Boolean), you shouldn't compare it against TRUE *or* FALSE; if you
want to know if the return value from "my_func" is zero, compare it
against zero.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/10/87)

In article <13851@watmath.UUCP> jyegiguere@watmath.waterloo.edu (Eric Giguere) writes:
>          #define TRUE   ( 0 == 0 )
>          #define FALSE  ( 1 == 0 )
>The point here is that instead of letting the program arbitrarily
>decide what TRUE and FALSE should be, we let the compiler decide,
>which adds to the portability.

You're under a misconception; nothing whatever is gained by this.
See my next comment.

>In actual effect, the definition for FALSE above could just as well
>be replaced with
>          #define FALSE   0

Furthermore, you might have well written
	#define	TRUE	1
since (1 == 0) has precisely the value 1 in C.

In C expression evaluation, relationals and other nominally Boolean
operators produce either 0 or 1 for their value -- never anything
else.  In any context where the "truth" of an expression is being
tested (for example in an "if" condition), any non-zero expression
is considered to be "true" and only zero is considered "false";
thus testing for truth works with a superset of the values produced
by expressions that compute truth values.  All this is built into
the rules of the C language and is NOT up to the implementation.

I for one wish C had been designed with an explicit Boolean data
type distinct from integral types, but it wasn't.  I do find it
helpful to maintain the conceptual distinction in one's code,
however, never using an arithmetic expression where a relational
test (against 0) is called for, and never performing arithmetic on
conceptually Boolean data.  ("What, never?"  "No, never!"  "What,
never?!"  "Well, hardly ever!")

ron@topaz.rutgers.edu (Ron Natalie) (07/10/87)

Poeple seem to be missing the point.  If you are going to define
your own boolean type, it doesn't matter what you use for TRUE
and FALSE as long as you're consistant.  TRUE can be 't' and FALSE
could be 'f' as long as you always use them that way.

The problem is that C defines FALSE to be zero and TRUE to be non
zero.  Hence, while you may define FALSE to be 0, there is nothing
you can define true to be that will consistantly work as things that
set true values are free to use any non-zero number.  The correct test
for truth is the value by itself, for example

	    if(expr)
	    while(expr)
	    for(;expr;)
	    expr ? x : y

FALSE can either be !expr or expr == 0 (or its #define'd equivelents).

---------------------------------------------------------------------

On a different light, I've noticed nobody has mentioned the construct
of seting a variable of TRUE by incrementing it.  Many, many programs
process their options by code like the following:

	switch(*argv[1])  {
	case 'b':
	    bflag++;
	    break;

	case 'c':
	    cflag++;
	    break;

The flag variables are unitialized extern chars (and hence are zero).
Some times however, this approach is used inside of loops, I avoid using
this because I am always afraid that someday someone will cause the code
to be executed exactly 256 times.

-Ron

ron@topaz.rutgers.edu (Ron Natalie) (07/10/87)

FROM CTYPE.H (essentially similar in both System V and BSD):

#define	isupper(c)	((_ctype_+1)[c]&_U)

Guy, just since relational operators are defined to return 0 and 1,
does not mean that all truth values fall in this category.  If it
were, then the conditional expressions would have been trained to
only consider 0 and 1.

-Ron

jyegiguere@watmath.UUCP (07/12/87)

There have been some interesting comments, all valid.  Yes, in a 
proper implementation

     #define TRUE 1
     #define FALSE 0

should work properly.  The solution I offered was one that should
guarantee portability.  The use of an enumeration

    typedef enum { FALSE, TRUE } bool;

is fine as long as you're sure that your programs will only be used
on systems that support enumerations.  (Thankfully, most of them
do support it.)  I think, however, that lint is pretty picky if
it flags an expression of the form

     i = ( 0 == 0 );

which is perfectly valid if you read the grammar to the language.
Any decent compiler will simply fold this value into the appropriate
constant value.


------------------------

Eric Giguere

guy%gorodish@Sun.COM (Guy Harris) (07/12/87)

> There have been some interesting comments, all valid.  Yes, in a 
> proper implementation
> 
>      #define TRUE 1
>      #define FALSE 0
> 
> should work properly.  The solution I offered was one that should
> guarantee portability.

Nope.  If you assume that the implementation can get the definition
of the "==" operator wrong to the extent that "0 == 0" does not
evaluate to 1, and that to be safe you have to define TRUE as "0 ==
0", you should also assume that it can get the definition of the "+"
operator wrong so that "1 + 1" doesn't evaluate to 2.

The definition of the "==" operator is pretty clearly spelled out in
all descriptions of C; anybody who gets *that* wrong is capable of
just about any screwup.  Unless the quality of C implementations out
there is *so* dismal that C cannot be taken seriously as a portable
language for implementing software (in which case, you shouldn't
implementing software in C if you intend to port it), writing code
that "defends" against the possibility that an implementation of the
language is fundamentally flawed is silly (*and* does not "guarantee
portability" unless you defend against practically every screwup that
can be imagined), nor does assuming that the implementation is *not*
fundamentally flawed run the risk of unportability as you seem to be
implying here.

> I think, however, that lint is pretty picky if it flags an expression of
> the form
> 
>      i = ( 0 == 0 );
> 
> which is perfectly valid if you read the grammar to the language.
> Any decent compiler will simply fold this value into the appropriate
> constant value.

It's syntactically valid, but so what?  That's not the point.  "lint"
complains about this if it is asked to "Apply a number of heuristic
tests to attempt to intuit bugs, improve style, and reduce waste."
The key words here are "heuristic" and "intuit".  It is trying to
detect code that is syntactically valid, and perhaps even
semantically valid, but possibly wrong anyway.  This test will pick
up errors such as writing

	if (datum & MASK == VALUE)

rather than

	if ((datum & MASK) == VALUE)

to test whether a subfield of "datum" is equal to a particular value.
(This could be considered an argument in favor of bitfields; with
bitfields, you can directly express what you mean here, and not fact
the possibility of getting the test wrong.  You can't use bitfields
in all cases - if the format of "datum" is externally imposed, you
will probably need the mask, since the order in which bit fields are
placed within structure is implementation-dependent.)
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

guy%gorodish@Sun.COM (Guy Harris) (07/13/87)

> Guy, just since relational operators are defined to return 0 and 1,
> does not mean that all truth values fall in this category.

Ron, if you can find any claim that all truth values *do* fall into
that category in my posting, you have much better eyes than I do.  In
fact, I quote from that very posting:

	I presume that in this case "my_func()" returns something to be
	thought of as a Boolean, except that any non-zero value, not just 1,
	maps to TRUE.

The point is that if somebody's going to define TRUE and FALSE, *with
TRUE being the particular value of "true" generated by the relational
operators*, there's no point in defining TRUE as "0 == 0" instead of
"1".
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

dhesi@bsu-cs.UUCP (07/13/87)

Never test an expression against TRUE or FALSE.
-- 
Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

devine@vianet.UUCP (Bob Devine) (07/15/87)

In article <13851@watmath.UUCP>, jyegiguere@watmath.UUCP (Eric Giguere) writes:
> The way we define these at the Computer Systems Group here at UW
> (which we include in the <stdio.h> file for Waterloo C)
> is:
>           #define TRUE   ( 0 == 0 )
>           #define FALSE  ( 1 == 0 )

  This doesn't really gain you much.  FALSE is still recognized as 0
and TRUE can only be defined as non-zero.  Having the compiler fill in
the blanks is no step forward.

  For those who wrote code as "if (such_and_such == TRUE)" believing it
to really mean "if (such_and_such != FALSE)", the above does nothing.

Bob Devine

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/16/87)

In article <13259@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes:
>The problem is that C defines FALSE to be zero and TRUE to be non
>zero.  Hence, while you may define FALSE to be 0, there is nothing
>you can define true to be that will consistantly work as things that
>set true values are free to use any non-zero number.

This isn't quite precise.  There are two contexts: (a) setting a "true"
value; (b) testing the "truth" of a value.  When C specifies the former,
for example the value of a relational expression, it specifies that the
value will be either 0 or 1 (NOT "any non-zero value" for true); when C
specifies the latter, then indeed any non-zero value tests as "true".

>The correct test for truth is the value by itself ...

Right -- i.e., "if (expr)", NOT "if (expr == TRUE)".

>On a different light, I've noticed nobody has mentioned the construct
>of seting a variable of TRUE by incrementing it.

Yucky!  The principle "say what you mean" implies that "flag = TRUE;"
is much better than "flag++".  Note also that if one changes the initial
value of the flag (to have the option enabled by default, for example,
while leaving in support for the previous enabling option), the ++
approach gives it a funny value instead of the simple truth value 1.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/16/87)

In article <13260@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes:
>#define	isupper(c)	((_ctype_+1)[c]&_U)

One could legitimately consider that to be an implementation bug,
although the C spec only calls for these functions to return nonzero
if true rather than 1.  It does, however, prevent one from doing
arithmetic on these function values without first converting them
to 0/1 values (via ...!=0).  This doesn't bother me too much, since
I don't generally approve of arithmetic on Boolean data, but it is
unnecessarily sloppy.

Note that any reasonable compiler will generate the same code in
cases such as "if ( isupper( c ) )" when the macro is defined as:
	#define	isupper( c )	(((_ctype_ + 1)[c] & _U) != 0)
I'm considering making this change in my version of ctype.h, much
as I have already fixed up feof() and ferror() in stdio.h.

devine@vianet.UUCP (Bob Devine) (07/17/87)

In article <13259@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes:
>On a different light, I've noticed nobody has mentioned the construct
>of seting a variable of TRUE by incrementing it.

In article <6123@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> Yucky!  The principle "say what you mean" implies that "flag = TRUE;"
> is much better than "flag++".

  I've used this method many times -- but with a purpose in mind.
Doing it with a test allows a easy check for multiple use of a option.
For example, W_flag is set to 0 at the start and the following code
is inside of a getopt() loop.

    if (W_flag++)
    {
	 /* AI == Artificial Intimidation */
         printf("Don't type the W flag twice again.  Or else...\n");
	 exit(rand());
    }

steele@unc.cs.unc.edu (Oliver Steele) (07/19/87)

In article <208@vianet.UUCP> devine@vianet.UUCP (Bob Devine) writes:
>  I've used this method [writing "flag++" to set the boolean "flag" to
>true] many times -- but with a purpose in mind.  Doing it with a test
>allows a easy check for multiple use of a option.  For example, W_flag
>is set to 0 at the start and the following code is inside of a getopt()
>loop.
>
>    if (W_flag++)
>    {
>	 /* AI == Artificial Intimidation */
>         printf("Don't type the W flag twice again.  Or else...\n");
>	 exit(rand());
>    }

It's often more useful to have each use be a toggle (W_flag = !W_flag).
The default value of the flag can then be reversed by use of an alias or
an environment variable without locking the user into that default
choice.

------------------------------------------------------------------------------
Oliver Steele				  ...!{decvax,ihnp4}!mcnc!unc!steele
							steele%unc@mcnc.org

	"They're directly beneath us, Moriarty.  Release the piano!"

karl@haddock.ISC.COM (Karl Heuer) (07/20/87)

In article <208@vianet.UUCP> devine@vianet.UUCP (Bob Devine) writes:
>In article <6123@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
>> Yucky!  The principle "say what you mean" implies that "flag = TRUE;"
>> is much better than "flag++".
>
>[But] doing it with a test allows a easy check for multiple use of a option.
>    if (W_flag++) ...

One problem with this is that it's possible to overflow, the most likely case
being if you implement boolean with "char" and execute this statement 256
times.  (I know your example contained an "exit", but I'm thinking about the
general case.)

I agree with Doug.  I never use boolean "++" in my own code anymore, for the
reason he states and also because the notation is misleading: it suggests that
"--" can be used symmetrically as set-to-FALSE.

I'd rather have a true boolean datatype in the language, with "++" and "--"
defined as Set and Clear, respectively.  I've done this in C++.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

arnold@apollo.uucp (Ken Arnold) (07/21/87)

In article <13891@watmath.UUCP> Eric Giguere writes:
>I think, however, that lint is pretty picky if
>it flags an expression of the form
>
>     i = ( 0 == 0 );
>
>which is perfectly valid if you read the grammar to the language.
>Any decent compiler will simply fold this value into the appropriate
>constant value.

You seem to have missed the whole point of lint.  lint's job is not to
check for syntactic correctness.  Its job is to check for unusual
constructs which *are* syntactically correct, but which are potentially
bugs.  In the normal case, one does not say

	if (1 == 2)

If such a statement occurrs in the code, it is *probably* because
someone mistyped something, or possibly used a #define constant which
they didn't realize was a constant.  Thus, lint isn't being "pretty
picky" -- lint is doing its job.  Generally speaking, it's the C
compiler's job to check for syntax, and lint's job to check for
legal-but-questionable semantics.

The only case where lint will not complain about constants in
conditional context is

	while (1)

since this is a common construct used in place of

	for (;;)

for reasons which escape me personally, but seem obvious to the people
who do it.  (Please don't let's start an argument over this -- it is
as unimportant as the "i++" stuff, and I'm not attacking you personally
if you do this; I'm just insulting your mother :-)

Since it is an absolute C truth that any non-zero value is true, and
any zero value is false, there is no reason whatsoever to be cute and
use such a construct as "0 == 0" to get TRUE, since it is incorrect to
test against TRUE anyway.  Silicon Graphics did (and probably still
does) something like this, and it drove me up a wall and a half, since
it made it impossible to run lint on my code unless I #undef'ed TRUE
and FALSE, and the #define'ed them myself, which was ugly as sin and
twice as expensive (emotionally speaking).

		Ken Arnold

dparter@ccvaxa.UUCP (07/23/87)

steele@unc.cs.unc.edu writes:
[ refering to flag variables ... ]
> It's often more useful to have each use be a toggle (W_flag = !W_flag).
> The default value of the flag can then be reversed by use of an alias or
> an environment variable without locking the user into that default
> choice.

This is a double-edged sword:

	Suppose a `new' command (foo) is built on top of an existing, 
	well-known command (bar) using some of bar's 'toggle' flags, and 
	the documentation for foo says something like this:

		"... all other options are the same as for bar."

	The well-versed user, who knows that the flags for bar are
	really toggles, can use "foo -flag" to reverse the decision to make
	"-flag" the default.

	The typical user, knowing that he wants the "-flag" option when he 
	uses bar, not knowing it is the default for foo, nor that it is a
	toggle, uses "bar -flag" -- which does the exact opposite of what
	he wanted.... This situation is made worse by documentation that
	does not make it clear that the flags are really toggles, and by the
	indirection in the foo documentation.

--david

David W. Parter
gould/csd - urbana
uucp:	ihnp4!uiucdcs!ccvaxa!dparter
arpa:	dparter@gswd-vms.arpa --or-- dparter@gswd-vms.gould.com

peter@sugar.UUCP (Peter da Silva) (08/03/87)

I have seen programs where flags are turned off with '-' and on with '+'.
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)