Best Place to Define TRUE/FALSE

T

Thomas Dickey

Harald van D??k said:
C90 implementations are allowed to provide stdbool.h as an extension,
and platform-specific libraries may legitimately contain non-portable
code. ncurses is not wrong to include stdbool.h even in C90 mode.

ncurses includes stdbool.h if it is (by default) configured to support
C++ as well as C. X/Open states that curses.h defines TRUE and FALSE.
C++ has its own flavor. To make them work together (as well as have
the same binary interface), it includes headers and/or defines symbols
as needed.

(this is not intended to argue with the purists in this thread who
aren't concerned with actually writing code ;-)
 
M

Mark McIntyre

jacob navia said:


Chapter and verse, please, Mr Navia. (Translation: you're wrong.)

He is, but you could perhaps have been a little more informative. I
knew what you meant, but newbies might not have realised the
significance without a clue or two.
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
R

Richard Heathfield

Mark McIntyre said:
He is, but you could perhaps have been a little more informative.

Yes. I like to give people a chance to work it out for themselves if
possible. Alas, they rarely do. But *when* they do, it's worth it just to
see the look on their faces...
 
B

Ben Pfaff

Richard Heathfield said:
Yes. I like to give people a chance to work it out for themselves if
possible. Alas, they rarely do. But *when* they do, it's worth it just to
see the look on their faces...

Do you get a video feed for comp.lang.c, then? I haven't heard
about that feature.
 
T

Thomas Dickey

Thomas Dickey said:
ncurses includes stdbool.h if it is (by default) configured to support
C++ as well as C. X/Open states that curses.h defines TRUE and FALSE.
C++ has its own flavor. To make them work together (as well as have
^ (of "bool" - both in X/Open curses and C++)
 
C

Charles Richmond

CBFalconer said:
The point is that C99 has standardized those names in lower case,
so I advise jumping on the bandwagon and conforming to that. A
slight babel reduction.

It's blasphemy, I tell you!!!

How about if I use:

#include "stdbool.h"

#define TRUE true
#define FALSE false


;-)

(ISTM that the only decent thing for C99 to have done...
would be to standardize on *both* upper and lower case
for these. After all, what are you going to do with
TRUE *besides* use it to mean true???)
 
M

Malcolm McLean

Keith Thompson said:
Yevgen Muntyan said:
CBFalconer said:
Yevgen Muntyan wrote:
... snip ...
The following code doesn't compile with "gcc foo.c":

#include <stdbool.h>
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
typedef enum { false, true } bool;
#endif
int main (void)
{
return 0;
}
See the stdops.h header below. You should also test for __STDC__.
Use -W -Wall -ansi -pedantic with gcc.
[snip]

It (namely the code below) suffers from the very same problem.
__STDC_VERSION__ gets defined only if you use -std=c99, when it's
pointless. -ansi doesn't make it work.

--------------------------------------------------
#include <stdbool.h>

#ifndef stdops_h
#define stdops_h
#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
/* The following from C99 - must define for C90 */
#include <stdbool.h> /* define bool, true, false */
#include <iso646.h> /* define not, and, or */
#else
#define false 0
#define true 1
typedef int bool;
#define not !
#define and &&
#define or ||
#define xor ^
#endif
#endif

int main (void)
{
}

Right. If you add an unconditional "#include <stdbool.h>" to code
that carefully tests whether C99 is supported, it will break if
compiled in non-C99 mode. So don't do that.
The whole point of defining "true" and "false" is to make code easier to
read.
However we are treated to lines of complex conditional includes which need
even more tweaking if certain system characteristics are not met.
bool breaks libraries.
 
L

Lane Straatman

Malcolm McLean said:
Keith Thompson said:
Yevgen Muntyan said:
CBFalconer wrote:
Yevgen Muntyan wrote:
... snip ...
The following code doesn't compile with "gcc foo.c":

#include <stdbool.h>
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
typedef enum { false, true } bool;
#endif
int main (void)
{
return 0;
}
See the stdops.h header below. You should also test for __STDC__.
Use -W -Wall -ansi -pedantic with gcc.
[snip]

It (namely the code below) suffers from the very same problem.
__STDC_VERSION__ gets defined only if you use -std=c99, when it's
pointless. -ansi doesn't make it work.

--------------------------------------------------
#include <stdbool.h>

#ifndef stdops_h
#define stdops_h
#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
/* The following from C99 - must define for C90 */
#include <stdbool.h> /* define bool, true, false */
#include <iso646.h> /* define not, and, or */
#else
#define false 0
#define true 1
typedef int bool;
#define not !
#define and &&
#define or ||
#define xor ^
#endif
#endif

int main (void)
{
}

Right. If you add an unconditional "#include <stdbool.h>" to code
that carefully tests whether C99 is supported, it will break if
compiled in non-C99 mode. So don't do that.
The whole point of defining "true" and "false" is to make code easier to
read.
However we are treated to lines of complex conditional includes which need
even more tweaking if certain system characteristics are not met.
bool breaks libraries.
That's what Keith said: that the people who matter went for a macro that
makes _Bool the keyword, unless I misunderstand. I am certain that these
people realize that they can't make changes in the standard without breaking
_some library. LS
 
K

Keith Thompson

Keith Thompson said:
Yevgen Muntyan said:
CBFalconer said:
Yevgen Muntyan wrote:
... snip ...
The following code doesn't compile with "gcc foo.c":

#include <stdbool.h>
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
typedef enum { false, true } bool;
#endif
int main (void)
{
return 0;
}
See the stdops.h header below. You should also test for __STDC__.
Use -W -Wall -ansi -pedantic with gcc.
[snip]

It (namely the code below) suffers from the very same problem.
__STDC_VERSION__ gets defined only if you use -std=c99, when it's
pointless. -ansi doesn't make it work.

--------------------------------------------------
#include <stdbool.h>

#ifndef stdops_h
#define stdops_h
#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
/* The following from C99 - must define for C90 */
#include <stdbool.h> /* define bool, true, false */
#include <iso646.h> /* define not, and, or */
#else
#define false 0
#define true 1
typedef int bool;
#define not !
#define and &&
#define or ||
#define xor ^
#endif
#endif

int main (void)
{
}

Right. If you add an unconditional "#include <stdbool.h>" to code
that carefully tests whether C99 is supported, it will break if
compiled in non-C99 mode. So don't do that.

I think there's a real potential problem here that I haven't been
taking seriously enough.

The fact is, C99 conformance is not (currently) an all-or-nothing
thing. A number of implementations support some, but not all, C99
features. In particular, an implementation can support <stdbool.h>,
and possibly the _Bool keyword, without setting __STDC_VERSION__ to
indicate C99 conformance. This is probably even a reasonable thing to
do while working on full conformance.

For code written to work under such an implementation, it's likely
that some separately developed part of the program, such as a library
header will have a "#include <stdbool.h>" header. Since <stdbool.h>
defines false, true, and bool as macros, this can conflict with code
that attempts to define the same identifiers.

I think that adding #undef directives before attempting to define
these identifiers should fix at least part of the problem. Defining
them in a way as close to what <stdbool.h> does as possible is
probably also a good idea.

For example:

#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
#undef false
#undef true
#undef bool
#define false 0
#define true 1
#define bool int
#endif

All this can be put into a header file, say "mystdbool.h".

There *could* still be problems if the third-party code that uses
<stdbool.h> depends on attributes of _Bool (or bool) that don't apply
to int, such as the fact that converting any non-zero value to bool
yields 1.
 
L

Lane Straatman

Keith Thompson said:
Keith Thompson said:
Yevgen Muntyan said:
CBFalconer wrote:
Yevgen Muntyan wrote:
... snip ...
The following code doesn't compile with "gcc foo.c":

#include <stdbool.h>
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
typedef enum { false, true } bool;
#endif
int main (void)
{
return 0;
}
See the stdops.h header below. You should also test for __STDC__.
Use -W -Wall -ansi -pedantic with gcc.
[snip]

It (namely the code below) suffers from the very same problem.
__STDC_VERSION__ gets defined only if you use -std=c99, when it's
pointless. -ansi doesn't make it work.

--------------------------------------------------
#include <stdbool.h>

#ifndef stdops_h
#define stdops_h
#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
/* The following from C99 - must define for C90 */
#include <stdbool.h> /* define bool, true, false */
#include <iso646.h> /* define not, and, or */
#else
#define false 0
#define true 1
typedef int bool;
#define not !
#define and &&
#define or ||
#define xor ^
#endif
#endif

int main (void)
{
}

Right. If you add an unconditional "#include <stdbool.h>" to code
that carefully tests whether C99 is supported, it will break if
compiled in non-C99 mode. So don't do that.

I think there's a real potential problem here that I haven't been
taking seriously enough.

The fact is, C99 conformance is not (currently) an all-or-nothing
thing. A number of implementations support some, but not all, C99
features. In particular, an implementation can support <stdbool.h>,
and possibly the _Bool keyword, without setting __STDC_VERSION__ to
indicate C99 conformance. This is probably even a reasonable thing to
do while working on full conformance.

For code written to work under such an implementation, it's likely
that some separately developed part of the program, such as a library
header will have a "#include <stdbool.h>" header. Since <stdbool.h>
defines false, true, and bool as macros, this can conflict with code
that attempts to define the same identifiers.

I think that adding #undef directives before attempting to define
these identifiers should fix at least part of the problem. Defining
them in a way as close to what <stdbool.h> does as possible is
probably also a good idea.

For example:

#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
#undef false
#undef true
#undef bool
#define false 0
#define true 1
#define bool int
#endif

All this can be put into a header file, say "mystdbool.h".

There *could* still be problems if the third-party code that uses
<stdbool.h> depends on attributes of _Bool (or bool) that don't apply
to int, such as the fact that converting any non-zero value to bool
yields 1.
I would ask, at least rhetorically, how would you characterize a library
that fails in the face of the above preproceesor directives? Me, I would
call it junk. LS
 
K

Keith Thompson

Lane Straatman said:
I would ask, at least rhetorically, how would you characterize a library
that fails in the face of the above preproceesor directives? Me, I would
call it junk. LS

Not necessarily.

Assume the implementation provides a <stdbool.h> header that fully
conforms to C99, but the implementation as a whole does not. The
compiler supports the _Bool keyword (as an extension), and <stdbool.h>
has "#define bool _Bool".

One of your source files has the following:

....
#include "mystdbool.h"
#include "thirdpartylibrary.h"
....

and thirdpartylibrary.h has

#include <stdbool.h>

Then the "#define bool _Bool" in <stdbool.h> is a constraint
violation, because "bool" is already #defined as int.

The implementation could avoid the problem by #undef'ing false, true,
and bool in <stdbool.h>, but it's not required to do so.

It would be nice, I think, if it were possible to make a #include
directive conditional on whether the header exists. For example:

#if header_exists <stdbool.h>
#include <stdbool.h>
#else
#undef false
#undef true
#undef bool
#define false 0
#define true 1
#define bool int
#endif

Although typical real-world software does this by doing tests at build
time and generating source code based on the results (GNU autoconf is
an example). It's outside the scope of the C language, and it's not
necessarily entirely portable, but it's more flexible.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top