The lack of a boolean data type in C

C

CBFalconer

Default said:
And you can do it in C if that's desired, as mentioned elsewhere,
with bit arrays and few access macros.

In Pascal you just use a set. You might need an array of sets to
mimic lots and lots of booleans.
 
C

CBFalconer

Keith said:
.... snip ...

Of course that's not the whole story. A *lot* of programmers have
implemented their own Boolean types, by various names and with
various definitions. See section 9 of the comp.lang.c FAQ,
<http://www.c-faq.com/>, for some examples. The problem with that
is that types defined by different programmers may not be
compatible, and when their code is combined into a single program,
it has to be reconciled somehow. C99 added _Bool and <stdbool.h>
to bring some order to the situation *without* breaking any
existing solutions.

Which is why I wrote stdops.h (elsethread) as I did, to port those
same standards to C90.
 
M

Malcolm

Keith Thompson said:
Why is that a problem? I don't care what the machine code looks like,
as long as it implements the semantics correctly; efficiency is a
secondary concern, but I *still* don't usually care about the specific
instruction sequences.
A lot of C has to integrate with functions written in assembly. The fewer
hassles because datatypes have different storage depending on context the
better.
 
K

Keith Thompson

Eric Sosman said:
Keith said:
[...] C has the
convention that any scalar expression can be used as a condition (in
an if or while statement, or as an operand of "!", "||", or "&&"). If
the expression has the value zero, it's treated as false; if it has
any non-zero value, it's treated as true.
Given these conventions, a separate Boolean type simply is not
needed.
[...]

At some risk to topicality (but we're already discussing
"What-If C" anyhow), I'll mention that there's at least one
other popular language that gets along quite well without a
Boolean type, thank you very much. I refer to Lisp, in which
the value `nil' (roughly meaning "no value") is considered
false, while any non-`nil' ("any actual value") is true.

If I recall correctly, any non-'nil' value is true, but there is a
special true value called 't'.
 
K

Keith Thompson

CBFalconer said:
Default User wrote: [...]
And you can do it in C if that's desired, as mentioned elsewhere,
with bit arrays and few access macros.

In Pascal you just use a set. You might need an array of sets to
mimic lots and lots of booleans.

Or you can use a packed array of boolean. ("Packed" is standard,
right?) But sets do give you some handy operations.
 
R

Richard Bos

Keith Thompson said:
But C99 does have _Bool.

True, but I have yet to see any compelling reason to include it. I see
the reasons they had to do so; I don't find them particularly
compelling.

Richard
 
R

Richard Bos

Keith Thompson said:
If I recall correctly, any non-'nil' value is true, but there is a
special true value called 't'.

There is. Almost as in C, in fact: any non-zero value is true, but there
is a special true value called 1. The only difference is that in Lisp,
the special true and false values are not anything else _but_ boolean
values (but non-booleans can be used as booleans, all true), while in C,
the special true and false values are _also_ integers.

Richard
 
C

CBFalconer

Keith said:
CBFalconer said:
Default User wrote: [...]
And you can do it in C if that's desired, as mentioned elsewhere,
with bit arrays and few access macros.

In Pascal you just use a set. You might need an array of sets to
mimic lots and lots of booleans.

Or you can use a packed array of boolean. ("Packed" is standard,
right?) But sets do give you some handy operations.

Yes, but that just indicates a willingness to have storage packed,
it doesn't enforce it. It also means that access requires use of
the standard procedures pack and unpack. Something analagous to
getting the address of a register variable which requires copying
the variable into another one.

The biggest nuisance of sets is that there is no standard way to
determing the value of maxset other than RTFM. The better systems
ensure that a "SET OF char" is possible, but that is not
guaranteed, and there is also no standard way to evaluate
ord(MAXCHAR).

These are areas that C covers very nicely in <limits.h>.
 
E

Eric Sosman

There's nothing special about `t': it's just a non-`nil'
atom. In a "pure Boolean" situation where true/false is all
that matters and there's no additional information to impart,
the convention is to use `t' -- but it's just a convention,
like C's use of 1 when -42 would do; both are "true."
There is. Almost as in C, in fact: any non-zero value is true, but there
is a special true value called 1. The only difference is that in Lisp,
the special true and false values are not anything else _but_ boolean
values (but non-booleans can be used as booleans, all true), while in C,
the special true and false values are _also_ integers.

That's not right (or perhaps I've misunderstood you). The
value `nil' has meanings other than "false:" it also means "empty
list" and "no matching key in hash table" and "no more input" and
so on -- very roughly speaking, it has all the meanings C associates
with NULL (including "false") and with EOF.

The atom `t' is conventionally used for "true" when there's
nothing else of interest lying around, but it is in no way special
or devoted to Boolean uses only. The program is free to use `t'
in all the ways it could use other atoms like `a' and `x' and
`xyzzy'.
 
J

jacob navia

Arthur J. O'Dwyer a écrit :
jacob navia said:



Not at all. The names I chose for my macros make it perfectly clear what
they do.



So what? If ever it becomes a performance problem, I'll worry about it.
Until then, I'll write the code to be clear to a human reader, and let
the
compiler worry about how best to optimise it.


And FWIW, compilers are really smart. I'm biased,[1] but I assure you
that if the compiler has /any/ "optimizations specifically designed for
bit arrays", it will go out of its way to find (x = x&~m|y&m), even
hidden behind a macro, and make the obvious substitution.

-Arthur

[1] - working as I do, now, with an optimizing compiler for compiling
embedded software that's just packed with bitfield operations
(pun intended). I honestly have no idea whether GCC on x86 is anywhere
close to Green Hills on PowerPC in terms of bitfield ops.

Well I am porting to PowerPc lcc-win32. I have a working first version
and I am discovering the bitfield operations in that CPU.

I do not want to make the compiler overly complex. Green Hills has
probably a lot of code to discover those bitfield-extracting operations
from a series of ANDs and masking etc... Besides having somewhere
make a wrong "discovery" it is incredibly easy.

If we had true boolean arrays we could do that without making C
compilers more commplex taht they need to be.

jacob
 
K

Keith Thompson

CBFalconer said:
Keith said:
CBFalconer said:
Default User wrote: [...]
And you can do it in C if that's desired, as mentioned elsewhere,
with bit arrays and few access macros.

In Pascal you just use a set. You might need an array of sets to
mimic lots and lots of booleans.

Or you can use a packed array of boolean. ("Packed" is standard,
right?) But sets do give you some handy operations.

Yes, but that just indicates a willingness to have storage packed,
it doesn't enforce it. It also means that access requires use of
the standard procedures pack and unpack. Something analagous to
getting the address of a register variable which requires copying
the variable into another one.
[...]

At least in the (non-standard) versions of Pascal I've used, "pack"
and "unpack" weren't necessary. You could do something like this:

Vec: packed array(1 .. 100) of Boolean;
...
Vec[50] = True;
if Vec[50] then
...

and compiler would generate whatever code is necessary to get it
right. Pascal doesn't define array indexing in terms of pointer
artithmetic; in fact, it doesn't define pointer arithmetic.

(I claim this is marginally topical as a comparison to what C *could*
have defined, but didn't.)
 
A

Arthur J. O'Dwyer

Arthur J. O'Dwyer a écrit :
jacob navia said: [re: macros with << and & for bit array operations]
making it impossible for the compiler
to do any optimizations specifically designed for bit arrays.

So what? If ever it becomes a performance problem, I'll worry about it.
Until then, I'll write the code to be clear to a human reader, and let the
compiler worry about how best to optimise it.

And FWIW, compilers are really smart. I'm biased,[1] but I assure you
that if the compiler has /any/ "optimizations specifically designed for
bit arrays", it will go out of its way to find (x = x&~m|y&m), even
hidden behind a macro, and make the obvious substitution.

-Arthur

[1] - working as I do, now, with an optimizing compiler for compiling
embedded software that's just packed with bitfield operations
(pun intended). I honestly have no idea whether GCC on x86 is anywhere
close to Green Hills on PowerPC in terms of bitfield ops.

Well I am porting to PowerPc lcc-win32. I have a working first version
and I am discovering the bitfield operations in that CPU.

Yeah. I like "rlwimi". ;)
I do not want to make the compiler overly complex. Green Hills has
probably a lot of code to discover those bitfield-extracting operations
from a series of ANDs and masking etc... Besides having somewhere
make a wrong "discovery" it is incredibly easy.

If we had true boolean arrays we could do that without making C
compilers more commplex taht they need to be.

Unoptimizing compilers, sure. I totally agree that the more low-level
constructs a language provides natively, the better the code generated
by a stupid compiler can be.
However, in the Real World(tm), people are often (usually?) stupider
than their compilers, and even if C did provide bit-array operations
natively, there would be some poor fool[1] writing

#define FLAG1 0x20
x &= ~FLAG1;

and then wondering why his compiler doesn't use the "bclri" machine
instruction. So an optimizing compiler would still have to support both
methods: C's old bit flags and our new bit-array primitives. Ick.

my $.02,
-Arthur

[1] - Seen in someone else's code a while back:
/* Fill x with copies of the sign bit */
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
Go ahead, optimize /that/!
And for the C gurus: What's the cleanest way to do what that
programmer was doing, but still in standard C? The obvious solution,
x >>= 31;
isn't guaranteed to work for signed numbers.
 
K

Keith Thompson

Arthur J. O'Dwyer said:
[1] - Seen in someone else's code a while back:
/* Fill x with copies of the sign bit */
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
Go ahead, optimize /that/!
And for the C gurus: What's the cleanest way to do what that
programmer was doing, but still in standard C? The obvious solution,
x >>= 31;
isn't guaranteed to work for signed numbers.

Assuming the comment is correct:

if (x < 0) {
x = INT_MIN;
}
else {
x = 0;
}

substituting the proper constant for INT_MIN.
 
D

Denis Kasak

KimmoA said:
Well... even if it's entirely pointless, being able to tell to the
compiler that a variable can only ever be "on" or "off" would feel so
much better. Nobody else seems to care, though... Hmpf.

Why would you want to do something that would save neither data nor
execution time (or be of any use at all, for that matter)?

Have you understood that, as others have already pointed out, even the
compiler cannot implement the bool type 'natively'? It still has to
emulate it either by typedef'ing it to another type or by packing bools
into a bigger type. This is a limitation of the processor and/or memory.
In order to implement a truly 'native' Boolean type, your architecture
would need to be able to address each bit without any additional
overhead (without offsets, masking, etc). This is, of course, very
cumbersome to do as it would require fundamental changes in today's
computer architectures, all for little or no realistic gain.

As for your 'feels right' point, what's wrong with #include <stdbool.h>
or, if you don't have access to a compiler that supports _Bool, with
typedef'ing enum to bool?
 
R

Richard

jaysome said:
Richard said:
jaysome said:
My "workaround" has always been:

typedef unsigned char boolean;
#define FALSE 0
#define TRUE 1

This allows you to use these types of statments:

boolean oven_is_on;
oven_is_on = FALSE;
oven_is_on = TRUE;
if ( oven_is_on )
if ( !oven_is_on )
char *OVEN_STRINGS[2] = {"OFF", "ON"};
printf("Oven is %s\n", OVEN_STRINGS[oven_is_on]);

But your OVEN_STRINGS argument to printf is not defined.

The code is probably intended as a series of fragments, but ignoring
that, since you did too:

Yes, fragments.
Firstly, there is no argument to printf. There is a syntax error.

Huh?

The prototype for printf() is:

int printf(const char *format, ...);

How is the above a syntax error?

They are picking holes : you should have specifically said that the code
was a non compilable example of how you tend to use your boolean types
to index into an array of text representations for on & off. Even then
someone would probably have told you off : don't worry - it's typical
nit picking anal retentiveness. It was fairly obvious to anyone who read
that far down the thread what you meant.
 
C

Chris Hills

Denis Kasak said:
Why would you want to do something that would save neither data nor
execution time (or be of any use at all, for that matter)?

Have you understood that, as others have already pointed out, even the
compiler cannot implement the bool type 'natively'? It still has to
emulate it either by typedef'ing it to another type or by packing bools
into a bigger type. This is a limitation of the processor and/or
memory. In order to implement a truly 'native' Boolean type, your
architecture would need to be able to address each bit without any
additional overhead (without offsets, masking, etc). This is, of
course, very cumbersome to do as it would require fundamental changes
in today's computer architectures, all for little or no realistic gain.

As it happens the worlds most common MCU does have bit addressable
memory and bit types. That aside the rest of your argument holds true
as most MCU /CPU don't have bit addressable memory

Because of this there are such things as signed and unsigned bit
types... IT the Bit type is in a larger memory type and therefore can
have a sign bit.
As for your 'feels right' point, what's wrong with #include <stdbool.h>
or, if you don't have access to a compiler that supports _Bool, with
typedef'ing enum to bool?

Sounds sensible to me,
 
M

Malcolm McLean

Chris Hills said:
Because of this there are such things as signed and unsigned bit types...
IT the Bit type is in a larger memory type and therefore can have a sign
bit.
That's an important philsophical issue.
In a set bit the msb is set, so in two's complement notation it is -1.
 

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