stdbool.h


B

Ben Bacarisse

Malcolm McLean said:
You're assuming that we can find programmers with English literature degrees
who understand clear communication, and also of course technical degrees
so they understand the mathematical side of what they are doing.

No I'm not.
You can maybe get the odd such person. But, generally, a name like
EnableControl() is meaningful to the person writing the function. Enabling
shares substantial logic with disabling, so it's easier to provide the same
function. And we've only got one control.
But to the maintaining programmer

EnableControl(0);

might mean "enable control with index zero". He knows we've
only got one control. Fair enough, that's in for expansion.

I chose EnableControl() because it's a common real example. Plenty of APIs
have it.

With software engineering, the trivial is important. It's not so much than
any one feature is unacceptably bad. It's the interaction of such features.

Consider this.

SetControlState(CONTROL_DISABLED);

acceptable, but a bit confusing, because you can't pass anything except
CONTROL_ENABLED or CONTROL_DISABLED.

Now

SetControlState(true);

the reader is completely in the dark. The bool has interacted with a poor
choice of name to make something very confusing.

I still don't get it. Why is SetControlState(true) any more confusing
that SetControlState(1) or SetControlState(42)?

I argued that this is a general problem: magic constants are almost
always a bad idea and that applies to true and false as much as to 0 or
42. I made a subsidiary remark that there are some cases where we don't
mind: i+1 and set_bit(n, true) both seem reasonable to me.

Is your point that API designers are somehow tempted into not providing
explanatory names for some Boolean parameters where they would have
thought to do so for integer ones? If so, I won't argue the point --
that may be the case, and I have no evidence one way or the other.
 
Ad

Advertisements

H

Helmut Tessarek

Is your point that API designers are somehow tempted into not providing
explanatory names for some Boolean parameters where they would have
thought to do so for integer ones? If so, I won't argue the point --
that may be the case, and I have no evidence one way or the other.

I think you guys are discussing a metaphysical problem. It all depends on the
project and the people who are participating, but in general I tend to use a
more pragmatic approach.

boolean variables make sense as arguments and as return values. If used as an
argument the function name is more important than the argument name itself.

e.g.:

SetControlState(true) <=> UnsetControlState(false)
UnsetControlState(true) <=> SetControlState(false)

Fact is that I can represent more than 2 states with magic constants, with
booleans there are only 2 states: on/off, true/false, yes/no. So depending on
the situation one concept is always more beneficial than the other.

Just my 2 cents.

--
Helmut K. C. Tessarek

/*
Thou shalt not follow the NULL pointer for chaos and madness
await thee at its end.
*/
 
T

Tim Rentsch

Jorgen Grahn said:
I'm sitting with a C99 code base and thinking about introducing
<stdbool.h>, the 'bool' type and true/false. Anything special I
have to keep in mind?

Am I likely to end up in conflict with people who feel stdbool.h
is an abomination? More than other C99 features, that is.

My background is in C++ where I of course use bool a lot. In C I tend
to use naked ints for booleans, and 0 and 1 when I need a true or
false constant. Works well, but it's not exactly self-documenting.

I must admit to a certain uneasiness to using 'true' and 'false'
as what are essentially manifest constants. They look too much
like they might be variables; in C programs, TRUE and FALSE seem
more in keeping with the culture. (Using 'bool' as a type name
is probably okay.)

Having said that, if you want to introduce 'bool', 'true', and
'false' into C99 programs, go ahead and do that. However, I
would suggest not using <stdbool.h> but rather defining the three
names yourself (in a regular header file) without using the
preprocessor, eg,

typedef _Bool bool;
enum { true = 1, false = 0 };

In C++, bool, true, and false are part of the language, and
always have the same meaning. In C, <stdbool.h> defines
these names as macros. Besides possibly interfering with
otherwise perfectly reasonable local uses, defining the
names as macros is likely to produce rather cryptic error
messages (or worse?) in cases where these names are used
in ways not in keeping with the #define'd values. Defining
the names as regular identifiers rather than preprocessor
names avoids these problems.

One other comment: if you do use 'bool', it should always
be a synonym for _Bool, never for another integer type,
because of the different semantics involved. I expect you
are already of the same opinion, but I believe the point
bears repeating for those who have not yet had the pleasure
of encountering problems that might ensue from confusing
the different semantics involved.
 
D

David Brown

I must admit to a certain uneasiness to using 'true' and 'false'
as what are essentially manifest constants. They look too much
like they might be variables; in C programs, TRUE and FALSE seem
more in keeping with the culture. (Using 'bool' as a type name
is probably okay.)

All-caps may be in common use in C, but that does not make it a good
idea. It is a relic from the days of computers without small letters,
and from before C had "const" or "enum".

In the modern world, "true" and "false" do not look like variables
because the choice of name makes it obvious, because the compiler will
enforce their consistency, and because there is a good chance that your
editor will pick fonts, colours, or other context-sensitive information
showing them to be constants. We don't need our software to shout at us
by using all-caps, nor draw unnecessary attention to the use of
particular identifiers.

Having said that, if you want to introduce 'bool', 'true', and
'false' into C99 programs, go ahead and do that. However, I
would suggest not using <stdbool.h> but rather defining the three
names yourself (in a regular header file) without using the
preprocessor, eg,

typedef _Bool bool;
enum { true = 1, false = 0 };

I see no justification for this idea. These identifiers are part of the
C language, as provided in the standards-mandated standard header.
Making your own versions is at best a duplication of effort, at worst it
is an invitation to people to invent their own implementation of these
symbols.
In C++, bool, true, and false are part of the language, and
always have the same meaning. In C, <stdbool.h> defines
these names as macros. Besides possibly interfering with
otherwise perfectly reasonable local uses, defining the
names as macros is likely to produce rather cryptic error
messages (or worse?) in cases where these names are used
in ways not in keeping with the #define'd values. Defining
the names as regular identifiers rather than preprocessor
names avoids these problems.

The C language - rightly or wrongly - defines _Bool to be a type large
enough to store the values 0 and 1. It is not an enumerated type. I
think it might have been advantageous to define it as "typedef enum {
false = 0, true = 1 } bool;", or to introduce new keywords like in C++.
But that is not the way it was done. That is (I presume) why the
standards say that these identifiers be macros.

I can't imagine any "perfectly reasonable local uses" of bool, true or
false that conflict with this, nor can I imagine any cryptic error
messages as a result. If you can provide examples, maybe I'll change my
mind.
 
J

jacob navia

Le 10/03/2014 00:22, David Brown a écrit :
The C language - rightly or wrongly - defines _Bool to be a type large
enough to store the values 0 and 1. It is not an enumerated type. I
think it might have been advantageous to define it as "typedef enum {
false = 0, true = 1 } bool;", or to introduce new keywords like in C++.
But that is not the way it was done. That is (I presume) why the
standards say that these identifiers be macros.

I can't imagine any "perfectly reasonable local uses" of bool, true or
false that conflict with this, nor can I imagine any cryptic error
messages as a result. If you can provide examples, maybe I'll change my
mind.

I would second that.

Can you give an example Tim?

I agree with David also that is a bad idea not to use the standard
header. I just do not see the problem that could arise.
 
K

Keith Thompson

David Brown said:
All-caps may be in common use in C, but that does not make it a good
idea. It is a relic from the days of computers without small letters,
and from before C had "const" or "enum".

In the modern world, "true" and "false" do not look like variables
because the choice of name makes it obvious, because the compiler will
enforce their consistency, and because there is a good chance that your
editor will pick fonts, colours, or other context-sensitive information
showing them to be constants. We don't need our software to shout at us
by using all-caps, nor draw unnecessary attention to the use of
particular identifiers.

Use of all-caps *for macros* is still a good idea, because of the
potential they have to do violence to the language syntax and semantics.
Consider, for example:

#define MAX(x, y) ( (x) >= (y) ? (x) : (y) )

The all-caps name makes it clear that something odd could be going on --
in this case, that one of the arguments will be evaluated twice.

And it's a well established convention (though one that the standard
library doesn't consistently follow).
I see no justification for this idea. These identifiers are part of the
C language, as provided in the standards-mandated standard header.
Making your own versions is at best a duplication of effort, at worst it
is an invitation to people to invent their own implementation of these
symbols.

I agree. For a compiler without _Bool, my favorite way to define a
boolean type is

typedef enum { false, true } bool;

The C language - rightly or wrongly - defines _Bool to be a type large
enough to store the values 0 and 1. It is not an enumerated type. I
think it might have been advantageous to define it as "typedef enum {
false = 0, true = 1 } bool;", or to introduce new keywords like in
C++. But that is not the way it was done. That is (I presume) why
the standards say that these identifiers be macros.

There is a significant difference between an enum type and _Bool;
conversion to the latter can only yield 0 or 1 (barring undefined
behavior). Though I try to avoid writing code that depends on that
(more for the sake of clarity than for portability).

The obvious way to introduce a boolean type to the language would have
been the C++ approach, making bool, false, and true all keywords. But
that would have broken existing code. The existing solution (adding
_Bool as a built-in type, and bool, false, and true as macros in
<stdbool.h>) is probably about the best that could have been done given
that constraint. (Though I would have made bool a typedef rather than a
macro.)

[...]
 
Ad

Advertisements

J

James Kuyper

On 09/03/14 23:17, Tim Rentsch wrote: .....

All-caps may be in common use in C, but that does not make it a good
idea. It is a relic from the days of computers without small letters,
and from before C had "const" or "enum".

A naming convention that reserves upper case for one purpose and lower
case for other purposes (and it is precisely such a convention that Tim
was referring to) cannot be explained by reference back to the days when
only one case was available. It requires a minimum of two different
cases in order to follow such a convention.
 
A

ais523

jacob said:
Le 10/03/2014 00:22, David Brown a écrit :

I would second that.

Can you give an example Tim?

I agree with David also that is a bad idea not to use the standard
header. I just do not see the problem that could arise.

I'm not Tim, but on some code I'm maintaining (that actually originally
predates C89; prototypes were only added to it recently), "bool" is a
typedef for some sort of char (not sure offhand whether it's signed,
unsigned, or plain), and structures are serialized using the equivalent
of fread/fwrite (a dubious practice that means that the serialization
format cannot easily be changed, and which also introduces
implementation-dependent behaviour for no good reason). Occasionally,
the original programmers ended up needing to store additional
information in the serialization format, without breaking backwards
compatibility; and their approach was to use the "spare bits" in the
booleans!

If I replaced the char-style booleans with _Bool in that codebase, it
would cause some subtle breakage that might not be noticed immediately
(although the compiler might be clever enough to notice a bitwise-and of
a _Bool against 2 and produce a diagnostic; I haven't tested that), in
that the extra bits wouldn't fit into a _Bool in a sensible way (all the
offending fields would have to be identified and converted to unsigned
char, most likely). I'm not even sure what happens if you fread an
inappropriate bit pattern into a _Bool, offhand (it wouldn't surprise me
if that were undefined behaviour).
 
D

David Brown

I'm not Tim, but on some code I'm maintaining (that actually originally
predates C89; prototypes were only added to it recently), "bool" is a
typedef for some sort of char (not sure offhand whether it's signed,
unsigned, or plain), and structures are serialized using the equivalent
of fread/fwrite (a dubious practice that means that the serialization
format cannot easily be changed, and which also introduces
implementation-dependent behaviour for no good reason). Occasionally,
the original programmers ended up needing to store additional
information in the serialization format, without breaking backwards
compatibility; and their approach was to use the "spare bits" in the
booleans!

If I replaced the char-style booleans with _Bool in that codebase, it
would cause some subtle breakage that might not be noticed immediately
(although the compiler might be clever enough to notice a bitwise-and of
a _Bool against 2 and produce a diagnostic; I haven't tested that), in
that the extra bits wouldn't fit into a _Bool in a sensible way (all the
offending fields would have to be identified and converted to unsigned
char, most likely). I'm not even sure what happens if you fread an
inappropriate bit pattern into a _Bool, offhand (it wouldn't surprise me
if that were undefined behaviour).

That's fair enough - you are dealing with pre-C99 code. It is not
surprising that the it has its own definitions for bool, true and false
that could conflict with the C99 standard ones. (The original question
started "I'm sitting with a C99 code base and thinking about introducing
<stdbool.h>".)

I am not sure that the usage here is "perfectly reasonable local uses",
certainly by C99 standards, but I guess that's a matter of taste.
 
D

David Brown

Use of all-caps *for macros* is still a good idea, because of the
potential they have to do violence to the language syntax and semantics.
Consider, for example:

#define MAX(x, y) ( (x) >= (y) ? (x) : (y) )

The all-caps name makes it clear that something odd could be going on --
in this case, that one of the arguments will be evaluated twice.

There is a simple answer here - don't write code that has side effects
inside function arguments (such as MAX(x++, y++)). Also, avoid writing
general function-like macros that might cause trouble if people /do/
call them with side-effect arguments. With modern C, static inline
functions can replace many function-like macros with a clearer and safer
alternative. And if you really need generic handling of different
types, there are several possibilities (gcc "typeof", C11 _Generic, C++
templates) - although these all have obvious disadvantages.
And it's a well established convention (though one that the standard
library doesn't consistently follow).

It is an established convention, but that does not make it a good thing
(although clearly it has the advantage that people will be unsurprised
by it).

I can find no valid reason - beyond "history" and "convention" - to make
style distinctions:

#define MAX_NUMBER_OF_ITEMS 10
static const int max_number_of_items = 10;
enum { max_number_of_items = 10 };

In most cases, these three identifiers can be used in the same way and
the same places, give the same resulting code, and have the same
compiler-enforced read-only nature. Why should one of them be in
all-caps, making it stand out far too much in the source code?


If I have a piece of code that has a MAX() macro, and I replace the
macro definition with a static inline function, should I go through all
the code and change "MAX(..)" to "max(..)" just because the macro has
turned into a function - even though it does exactly the same thing, and
generates exactly the same code? Conversely, if I want to change an
existing function into a macro do I then need to rename everything in
all-caps just to follow this convention?


I understand that many people use this convention, and I understand that
people think it gives them some sort of warning or protection against
mistakes with macros. I just don't agree with it - at least, not in
/my/ code. (And I know my view here is controversial.)
I agree. For a compiler without _Bool, my favorite way to define a
boolean type is

typedef enum { false, true } bool;

but the whole point of adding <stdbool.h> to the standard library is to
avoid the need to reinvent that particular wheel.
Yes.


There is a significant difference between an enum type and _Bool;
conversion to the latter can only yield 0 or 1 (barring undefined
behavior). Though I try to avoid writing code that depends on that
(more for the sake of clarity than for portability).

Fair enough.
The obvious way to introduce a boolean type to the language would have
been the C++ approach, making bool, false, and true all keywords. But
that would have broken existing code. The existing solution (adding
_Bool as a built-in type, and bool, false, and true as macros in
<stdbool.h>) is probably about the best that could have been done given
that constraint. (Though I would have made bool a typedef rather than a
macro.)

I too would have had bool as a typedef - and false and true as
enumeration constants rather than macros (but as you noted above, bool
itself cannot be an enum). Perhaps the language could have defined
_True and _False as keywords for the type, equivalent to C++'s keywords,
and then put macros in <stdbool.h> to define true and false as _True and
_False rather than 1 and 0. But then the standards people might have
been tempted to say that the values of _True and _False, when converted
to integers, were implementation defined....
 
B

BartC

David Brown said:
On 10/03/14 01:10, Keith Thompson wrote:

It is an established convention, but that does not make it a good thing
(although clearly it has the advantage that people will be unsurprised
by it).

I can find no valid reason - beyond "history" and "convention" - to make
style distinctions:

#define MAX_NUMBER_OF_ITEMS 10
static const int max_number_of_items = 10;
enum { max_number_of_items = 10 };

In most cases, these three identifiers can be used in the same way and
the same places, give the same resulting code, and have the same
compiler-enforced read-only nature. Why should one of them be in
all-caps, making it stand out far too much in the source code?


If I have a piece of code that has a MAX() macro, and I replace the
macro definition with a static inline function, should I go through all
the code and change "MAX(..)" to "max(..)" just because the macro has
turned into a function - even though it does exactly the same thing, and
generates exactly the same code? Conversely, if I want to change an
existing function into a macro do I then need to rename everything in
all-caps just to follow this convention?

I understand that many people use this convention, and I understand that
people think it gives them some sort of warning or protection against
mistakes with macros. I just don't agree with it - at least, not in
/my/ code. (And I know my view here is controversial.)

This is far too sensible a point of view for comp.lang.c!

I don't like uses of upper case like this because it make code ugly.

(Also it encourages people to use upper and lower case versions of the same
name for different purposes. I know many will see that as an advantage.
Although that is more a consequence of C being case-sensitive.)

As for the MAX macro that is always brought up as an example, why doesn't
someone just throw in some actual min/max functions (or ideally, operators)
into the language! That's if they are not in there already; I'm never quite
sure.
 
Ad

Advertisements

D

David Brown

This is far too sensible a point of view for comp.lang.c!

I don't like uses of upper case like this because it make code ugly.

(Also it encourages people to use upper and lower case versions of the same
name for different purposes. I know many will see that as an advantage.
Although that is more a consequence of C being case-sensitive.)

As for the MAX macro that is always brought up as an example, why doesn't
someone just throw in some actual min/max functions (or ideally,
operators) into the language! That's if they are not in there already;
I'm never quite sure.

gcc had max and min operators as extensions, but I believe they are
deprecated these days.

There is no way that C could introduce min and max as operators or
keywords - it would cause too many conflicts. It would be possible to
add them to a standard library header - it wouldn't need anything more
than a _Generic macro such as those in <tgmath.h>. It would fit well in
<stdlib.h>, where the abs() and div functions could also nicely be
replaced with _Generics.

On the other hand, if max() and min() were added as safe macros or
functions in some way, what then could be use as an example of the
dangers of side effects combined with macros? (Or am I being too
cynical? :)
 
S

Stefan Ram

ais523 said:
compatibility; and their approach was to use the "spare bits" in the
booleans!

Such an approach was also taken in early LISP
implementations, where a bit in a word indicated whether the
rest was an integer or a pointer IIRC. And I must admit that
this feels quite natural to me.

How would you implement a binary tree node whose leafs can
be small integers in a memory-efficient way?

union cr;
struct node { union cr left; union cr right; }
union cr { int value; struct node * pointer; };
ispointer( union cr * cr ) { return ????; }

Assume that you would know that on your architecture one bit
of a pointer lways is zero and that you only have very
little memory available. Wouldn't it be tempting, when you
are developing for a special hardware?
 
K

Keith Thompson

David Brown said:
On 10/03/14 01:10, Keith Thompson wrote: [...]
Use of all-caps *for macros* is still a good idea, because of the
potential they have to do violence to the language syntax and semantics.
Consider, for example:

#define MAX(x, y) ( (x) >= (y) ? (x) : (y) )

The all-caps name makes it clear that something odd could be going on --
in this case, that one of the arguments will be evaluated twice.

There is a simple answer here - don't write code that has side effects
inside function arguments (such as MAX(x++, y++)). Also, avoid writing
general function-like macros that might cause trouble if people /do/
call them with side-effect arguments. With modern C, static inline
functions can replace many function-like macros with a clearer and safer
alternative. And if you really need generic handling of different
types, there are several possibilities (gcc "typeof", C11 _Generic, C++
templates) - although these all have obvious disadvantages.

That's fine if the author of the macro definition and the author of
any code that uses it are the same person. I don't particularly
like side effects in function arguments, but it's not practical
to ban them -- and sometimes something like func(count++) is more
convenient than the alternative. An all-caps macro name is a
reminder to *avoid* arguments side effects.

If you're writing a header to be used by other programmers, and you
feel the need to define macros in that header, it's probably a good
idea to follow the conventions those other programmers are likely
to understand. (And yes, that's a slightly more sophisticated
version of "do it that way because I said so".)

Static inline functions can't replace MAX and MIN, which work for any
type with a ">=" operator. gcc's "typeof" is obviously not portable,
and template are not C. I suppose you could use _Generic in a macro
definition along with a collection of N functions to implement max
and min for N different types, but I don't think it would handle
arguments of different types.

In any case, if you're using something other than macros, the
all-caps convention isn't even relevant.
It is an established convention, but that does not make it a good thing
(although clearly it has the advantage that people will be unsurprised
by it).

I can find no valid reason - beyond "history" and "convention" - to make
style distinctions:

#define MAX_NUMBER_OF_ITEMS 10
static const int max_number_of_items = 10;
enum { max_number_of_items = 10 };

In most cases, these three identifiers can be used in the same way and
the same places, give the same resulting code, and have the same
compiler-enforced read-only nature. Why should one of them be in
all-caps, making it stand out far too much in the source code?

Most but not all. The name of a "static const int" object isn't a
constant expression, and an enumeration constant can only be of type
int.

If I see a reference to "max_number_of_items" without seeing its
definition, I'm likely to assume that it's a variable whose value might
be determined at execution time. If I see MAX_NUMBER_OF_ITEMS, I'll
assume it's a compile-time constant. The use of all-caps does convey
useful information to the reader. (Which admittedly doesn't cover the
enum case; I never claimed any of this was 100% consistent.)
If I have a piece of code that has a MAX() macro, and I replace the
macro definition with a static inline function, should I go through all
the code and change "MAX(..)" to "max(..)" just because the macro has
turned into a function - even though it does exactly the same thing, and
generates exactly the same code? Conversely, if I want to change an
existing function into a macro do I then need to rename everything in
all-caps just to follow this convention?

If you want to follow the convention strictly, yes. But it's only a
convention, and you don't have to follow it in your own code if you
don't want to.
I understand that many people use this convention, and I understand that
people think it gives them some sort of warning or protection against
mistakes with macros. I just don't agree with it - at least, not in
/my/ code. (And I know my view here is controversial.)
[...]
The obvious way to introduce a boolean type to the language would have
been the C++ approach, making bool, false, and true all keywords. But
that would have broken existing code. The existing solution (adding
_Bool as a built-in type, and bool, false, and true as macros in
<stdbool.h>) is probably about the best that could have been done given
that constraint. (Though I would have made bool a typedef rather than a
macro.)

I too would have had bool as a typedef - and false and true as
enumeration constants rather than macros (but as you noted above, bool
itself cannot be an enum). Perhaps the language could have defined
_True and _False as keywords for the type, equivalent to C++'s keywords,
and then put macros in <stdbool.h> to define true and false as _True and
_False rather than 1 and 0. But then the standards people might have
been tempted to say that the values of _True and _False, when converted
to integers, were implementation defined....

Making false and true (however they're defined) be of type _Bool/bool
would have been clean, but given C's rather, um, promiscuous implicit
conversions it wouldn't have made any difference 99% of the time.
Making them have type int is consistent with the treatment of both
character constants and enumeration constants.

I don't think there would have been any temptation to make the results
of conversions implementation-defined. Conversions of _Bool values to
integer types are well defined anyway -- and in fact _Bool *is* an
integer type.
 
T

Tim Rentsch

jacob navia said:
I would second that.

Can you give an example Tim?

Do you mean you don't see a possible advantage to defining an
identifier as a typedef or enum value rather than a macro?
Or that you can't think of such a situation that would apply
in the particular case of bool, true, or false?
 
D

David Brown

Do you mean you don't see a possible advantage to defining an
identifier as a typedef or enum value rather than a macro?
Or that you can't think of such a situation that would apply
in the particular case of bool, true, or false?

You said:

"In C++, bool, true, and false are part of the language, and
always have the same meaning. In C, <stdbool.h> defines
these names as macros. Besides possibly interfering with
otherwise perfectly reasonable local uses, defining the
names as macros is likely to produce rather cryptic error
messages (or worse?) in cases where these names are used
in ways not in keeping with the #define'd values. Defining
the names as regular identifiers rather than preprocessor
names avoids these problems."

We would like to see examples of such problems, or at least ideas about
how the standard macro definitions could cause problems while an enum
based one would avoid the problems - all within "perfectly reasonable"
code. /I/ can't think of any cases - so it would help me understand
your point if you could elaborate here.

David
 
Ad

Advertisements

A

ais523

Stefan said:
Such an approach was also taken in early LISP
implementations, where a bit in a word indicated whether the
rest was an integer or a pointer IIRC. And I must admit that
this feels quite natural to me.

How would you implement a binary tree node whose leafs can
be small integers in a memory-efficient way?

union cr;
struct node { union cr left; union cr right; }
union cr { int value; struct node * pointer; };
ispointer( union cr * cr ) { return ????; }

Assume that you would know that on your architecture one bit
of a pointer lways is zero and that you only have very
little memory available. Wouldn't it be tempting, when you
are developing for a special hardware?

Yes, that might be necessary, but I wouldn't claim that the resulting
code was anything like portable, standards-compliant C. I've written
C programs for processors with only a few kilobytes of memory before
now, some parts of which were sufficiently time-sensitive that I had
the assembler output open in another window and tweaked the input C
until the compiler produced the output I wanted. I don't really think
of that as C, though (at least partly because the compilers for such
architectures tend to be limited and buggy and full of extensions).
It's a language that's accepted by at least one C implementation, but
it's impossible to get it anywhere close to strictly conforming.

In the specific case of binary trees, I probaby wouldn't use something
as wasteful as pointers on such a limited system. Although the compilers
can handle pointers just fine, there isn't really room for a functioning
malloc system, so you're best off using a static array to store your
tree and using indexes into the array as your pointer-equivalents. (Or,
if the tree is approximately balanced, using an entirely different
storage method, such as is often used for heaps.)

I've also been burned by nonportable code plenty of times in the past.
Right now, when writing C, I aim for compliance with the standards if at
all possible; pretty much my minimum standard of portability for new
projects is "the code, minus any libraries it needs to run, is strictly
conforming C11; and any features in the code that weren't in C89 must
have been supported as extensions in gcc and clang for the last
several years". Typically I also rely on POSIX for the supporting
libraries when possible, and try to confine it to a minimum of files.
 
J

jacob navia

Le 10/03/2014 18:12, Tim Rentsch a écrit :
Do you mean you don't see a possible advantage to defining an
identifier as a typedef or enum value rather than a macro?

Not in this case, no. That's why I asked the question that you don't
actually answer.

One advantage of the macro is that you can undefine it. You can't do
that with a typedef.
Or that you can't think of such a situation that would apply
in the particular case of bool, true, or false?

No, I can't, and I think you can't either...

:)
 
E

Eric Sosman

[...]
Assume that you would know that on your architecture one bit
of a pointer lways is zero and that you only have very
little memory available. Wouldn't it be tempting, when you
are developing for a special hardware?

Someone I used to know once did that trick with a big array
of function pointers. Since function pointers always point to
the function's first instruction, and since instructions always
start on word boundaries (he "knew" this to be true, understand?),
he used the low-order pointer bit as a flag to indicate which
functions actually needed to run on the current pass and which
could be skipped.

I discovered this awfulness when porting his code to the VAX,
on which *neither* of the things he "knew" held true ...
 
Ad

Advertisements

T

Tim Rentsch

David Brown said:
All-caps may be in common use in C, but that does not make it a
good idea.

Different developers have different opinions on that point, but
in any case it's irrelevant to what I was saying.
It is a relic from the days of computers without small letters,

Nonsense, as James Kuyper has pointed out.
and from before C had "const" or "enum".

That has no bearing on my comment.
In the modern world, "true" and "false" do not look like
variables because the choice of name makes it obvious, because
the compiler will enforce their consistency, and because there is
a good chance that your editor will pick fonts, colours, or other
context-sensitive information showing them to be constants. We
don't need our software to shout at us by using all-caps, nor
draw unnecessary attention to the use of particular identifiers.

Are you always so parochial? Is it so hard for you to imagine
that other developers might have different opinions on these
topics?
I see no justification for this idea. These identifiers are part
of the C language, as provided in the standards-mandated standard
header.

The header <stdbool.h> is part of a standard implementation, but
use of <stdbool.h> is optional, not mandatory. Moreover, the
Standard gives explicit and specific permission to undefine the
macros bool, true, and false from <stdbool.h>, so obviously the
Standard anticipates that some developers would want to do that
for one or more of those symbols, and perhaps define their own
Making your own versions is at best a duplication of effort,
at worst it is an invitation to people to invent their own
implementation of these symbols.

You're engaging in hyperbole. What I am doing is pointing out
alternate definitions for bool, true, and false, with somewhat
different characteristics for how the identifiers can be used,
that may be preferable in some circumstances. If some
developers find that their own circumstances favor those
different characteristics, they may reasonably prefer to use
those alternate definitions; in other circumstances they may
reasonably prefer to use the <stdbool.h> definitions. The
choice is up to them. Under some circumstances (which I will
not describe), I would advocate using using the <stdbool.h>
definitions; in others I would advocate using the alternate
definitions mentioned above. IMO this question should not be
given a "one size fits all" kind of answer.
The C language - rightly or wrongly - defines _Bool to be a type
large enough to store the values 0 and 1. It is not an enumerated
type. I think it might have been advantageous to define it as
"typedef enum { false = 0, true = 1 } bool;", or to introduce new
keywords like in C++. But that is not the way it was done. That
is (I presume) why the standards say that these identifiers be
macros.

The idea that bool might or should be an enumerated type has
no bearing on my comments.
I can't imagine any "perfectly reasonable local uses" of bool, true or
false that conflict with this, nor can I imagine any cryptic error
messages as a result. If you can provide examples, maybe I'll change
my mind.

I think you have missed the point of what I've been saying. In
any case I cannot be responsible for your lack of imagination.
 

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

Top