Esoteric definitions of TRUE and FALSE

E

Eric Sosman

[...]
So what would you recommend in the case of inherited legacy code like
this?

typedef enum bool_n {QFALSE, QTRUE} qboolean;
...

qboolean IsFemale (edict_t *ent)
{
char *info;

if (!ent->client)
return QFALSE;

info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
if (info[0] == 'f' || info[0] == 'F')
return QTRUE;
return QFALSE;
}

I'd recommend leaving it alone, unless you have some other
reason to make changes. "If it ain't broke, don't fix it." If
you decide to visit the code for some other reason -- maybe to
add a check for `info == NULL', say -- then you might consider
replacing qboolean at the same time. If you decide to ditch it,
you might do it this way

int IsFemale (const edict_t *ent) {
char *info;
if (ent->client == NULL)
return 0;
info = Info_ValueForKey (ent->client->pers.userinfo,
"skin");
return info != NULL
&& (*info == 'f' || *info == 'F');
}

Note that two of the three explicit uses of a truth constant have
vanished; this kind of simplification is often available when tests
produce manifest Boolean results. You could even get rid of the
one remaining occurrence:

int IsFemale (const edict_t *ent) {
char *info;
return ent->client != NULL
&& (info =
Info_ValueForKey (ent->client->pers.userinfo,
"skin")) != NULL
&& (*info == 'f' || *info == 'F');
}

.... but I think this breaches the bounds of good taste.
 
S

Spiros Bousbouras

Geoff said:
I've come across a library which defines TRUE and FALSE thus. [snip]

There is no good reason to do that.

See section 9 of the comp.lang.c FAQ, <http://c-faq.com/>.

In the absence of <stdbool.h>, my favorite form is

typedef enum { false, true } bool;

So what would you recommend in the case of inherited legacy code like
this?

typedef enum bool_n {QFALSE, QTRUE} qboolean;
...

qboolean IsFemale (edict_t *ent)
{
char *info;

if (!ent->client)
return QFALSE;

info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
if (info[0] == 'f' || info[0] == 'F')
return QTRUE;
return QFALSE;
}
[...]

Rather than

if (info[0] == 'f' || info[0] == 'F')
return QTRUE;
return QFALSE;

I'd have written:

return (info[0] == 'f' || info[0] == 'F');

(perhaps without the parentheses). Implicit conversion will
reliably convert the int result of the condition to qboolean.

Nahhh , that's risky. It depends on (info[0] == 'f' || info[0] == 'F')
having the same value as QTRUE. If the value of QTRUE changes for some
weird reason then you have a bug. If one is going to have explicit
constants to denote true and false then one should use them
consistently.
 
L

luser- -droog

Keith said:
...
I'd omit the tag "bool_n" on the enum declaration; it's not necessary
and it's probably never used.

Though it probably is useless here, I often find enum tags to be
useful
when inspecting values from the debugger. If I see a 17 that I know
should
be a certain kind of symbol, I can print it with a cast.

gdb> print (enum e_type)17

I don't think this would work without a tag.
 
G

Geoff

Though it probably is useless here, I often find enum tags to be
useful
when inspecting values from the debugger. If I see a 17 that I know
should
be a certain kind of symbol, I can print it with a cast.

gdb> print (enum e_type)17

I don't think this would work without a tag.

In this particular case it's there to make browsing in Visual Studio's
class browser easier. Untagged structs and enums get names assigned
like __unnamed_struct_0095_1. It's much easier to find and
double-click a tag to get to the definitions when they all have
sensible names. Anonymous enums can also be hard to find in large
projects so tagging them is helpful in the long run:

enum pmenu_n
{
PMENU_ALIGN_LEFT,
PMENU_ALIGN_CENTER,
PMENU_ALIGN_RIGHT
};

Xcode recognizes both tags and types in its symbol browser but the
search capability is better so it matters less.
 
K

Keith Thompson

luser- -droog said:
Though it probably is useless here, I often find enum tags to be
useful
when inspecting values from the debugger. If I see a 17 that I know
should
be a certain kind of symbol, I can print it with a cast.

gdb> print (enum e_type)17

I don't think this would work without a tag.

Actually, it does; gdb recognizes casts with typedef names.
For example:

(gdb) p (enum bool_n) 1
$1 = QTRUE
(gdb) p (qboolean) 1
$2 = QTRUE

Other tools might have problems with untagged enums, but in any case
there's probably no good reason to use distinct identifiers for the tag
and typedef:

typedef enum qboolean { QFALSE, QTRUE } qboolean;

And even if *that* causes problems for some tools, you can at least use
a consistent naming scheme for tags and typedefs:

typedef enum e_qboolean { QFALSE, QTRUE } qboolean;
 
S

Stefan Ram

Keith Thompson said:
are equally correct, but the shorter form is definitely *better*.

This I use a my general style guideline:

When two wordings are equivalent, use the shorter one.

More precise:

When two wordings are equivalent, and there is no other
strong reason to prefer one of them, use the shorter one.

Some say that DRY might be the most important style rule.

Don't Repeat Yourself.

Since a repetition usually lengthens a text, DRY might be
considered as a special case of the above rule, that might
be worded as »BC«:

Be Concise!
 
S

Stefan Ram

(e-mail address removed)-berlin.de (Stefan Ram) quotes:
nonzero (true)

This quotation from ISO/IEC 9899:1999 (E) might lead to
better define:

#define istrue( x )( x )
#define settrue( x )(( x )= 1 )
#define isfalse( x )!( x )
#define setfalse( x )(( x )= 0 )

instead of

#define true 1
#define false 0

. Or, possibly, if you prefer:

#define istrue( x )!!(x)
 
N

Noob

Michael said:
I don't happen to agree with it, but the reason for defining the TRUE
macro as (1==1) would be that you can be assured that the compiler
will evaluate (1==1) to true and, if you ever need to compare that
value (some implementations might give -1 for the result), you will
always get the right value.

Hmmm... IMHO, working around broken compilers is not a legitimate
reason to write strange-looking code.

3.3.8 Relational operators

Constraints

Each of the operators < (less than), > (greater than), <= (less
than or equal to), and >= (greater than or equal to) shall yield 1 if
the specified relation is true and 0 if it is false./38/ The result
has type int.

3.3.9 Equality operators

Semantics

The == (equal to) and the != (not equal to) operators are analogous
to the relational operators except for their lower precedence./39/

Regards.
 
J

James Kuyper

Michael Angelo Ravera wrote: .....

Just to emphasize the what you mean by "broken" below: any such
implementations are NOT standard-conforming implementations of C; they
might be implementations of some other, similar language.
Hmmm... IMHO, working around broken compilers is not a legitimate
reason to write strange-looking code.

Not even if, for some reason, you MUST use such a broken compiler,
perhaps because it's the only one currently available for a given
platform? Writing strange code is often unavoidable.

However, such code should be isolated in platform-specific sections of
the code. I agree that adopting such weird code practices as a general
rule, just because of one broken compiler, is not a good idea.
 
E

Eric Sosman

Just to emphasize the what you mean by "broken" below: any such
implementations are NOT standard-conforming implementations of C; they
might be implementations of some other, similar language.

Further to the point, such implementations (if they exist)
are not even "K&R Classic"-conforming. They're not today's C,
and they're not even yesterday's; they're never-never-C.
 
K

Kenny McCormack

Hmmm.. I just wrote one last night that did.

You mean you wrote here *about* an ancient compiler which did.[/QUOTE]

Hmmmm. Did I do that as well? I don't remember, but then again, I write so
many brilliant things over the course of time, that I can't be expected to
remember them all.
But as others replied, that compiler was horribly broken. It shouldn't
affect how people write C code today.

Anyway, my compiler is available if you're interested.
 
S

Stefan Ram

Kenneth Brody said:
Actually, I was the one who wrote about the early-1980's C compilers I used,
where (at least) one of them used -1 rather than 1. I don't know if you
could say there really was a "standard" C at the time.

Is it possible that you might confuse this with BASIC,
which was popular these days and used -1 for 1=1?
 
B

Ben Bacarisse

Kenneth Brody said:
Jorgen Grahn said:
On Sat, 2011-03-05, Kenny McCormack wrote:
I don't happen to agree with it, but the reason for defining the TRUE
macro as (1==1) would be that you can be assured that the compiler
will evaluate (1==1) to true and, if you ever need to compare that
value (some implementations might give -1 for the result), you will
always get the right value.

No implementation of standard C will give -1 for the result of 1==1.

Hmmm.. I just wrote one last night that did.

You mean you wrote here *about* an ancient compiler which did.
But as others replied, that compiler was horribly broken. [...]

It also wasn't standard C.

Actually, I was the one who wrote about the early-1980's C compilers I
used, where (at least) one of them used -1 rather than 1. I don't
know if you could say there really was a "standard" C at the time.

The appendix of K&R was the reference manual for the language before the
ANSI and ISO standards. Any compiler claiming to implement C after 1978
would have to do so in accordance with that definition so I'd consider
the use of -1 to be either a serious bug or an indication that the
compiler was not aiming to implement C, but some variation thereof.

Prior to 1978, anyone implementing C would have to turn to the internal
AT&T "C Reference Manual". That, too, confirms that == etc yield 1 or 0
rather than anything else.

BCPL used -1 for true (well, it used all bits one which is not exactly
the same thing) but even C's predecessor, B, had changed to using 1 and
0 as the result of == and !=.
 
K

Keith Thompson

Kenneth Brody said:
Jorgen Grahn said:
On Sat, 2011-03-05, Kenny McCormack wrote:
I don't happen to agree with it, but the reason for defining the TRUE
macro as (1==1) would be that you can be assured that the compiler
will evaluate (1==1) to true and, if you ever need to compare that
value (some implementations might give -1 for the result), you will
always get the right value.

No implementation of standard C will give -1 for the result of 1==1.

Hmmm.. I just wrote one last night that did.

You mean you wrote here *about* an ancient compiler which did.
But as others replied, that compiler was horribly broken. [...]

It also wasn't standard C.

Actually, I was the one who wrote about the early-1980's C
compilers I used, where (at least) one of them used -1 rather
than 1. I don't know if you could say there really was a
"standard" C at the time.

Note that K&R1 was published in 1978, and it clearly states that
the relational and equality operators yield 0 or 1.

Going back before K&R1, there are several earlier documents linked
from <http://cm.bell-labs.com/cm/cs/who/dmr/>. The 1974 and 1975
versions of the C Reference Manual both explicitly state that they
yield 0 or 1. For that matter, so does the reference for B, C's
immediate ancestor. (The 1967 BCPL references says that false,
which is a keyword, is represented as all-bits-1.)

There wasn't a formal language standard at the time, but I'd still
say that the compiler was buggy if it claimed to be a C compiler.
 
T

Tim Rentsch

Eric Sosman said:
[...]
So what would you recommend in the case of inherited legacy code like
this?

typedef enum bool_n {QFALSE, QTRUE} qboolean;
...

qboolean IsFemale (edict_t *ent)
{
char *info;

if (!ent->client)
return QFALSE;

info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
if (info[0] == 'f' || info[0] == 'F')
return QTRUE;
return QFALSE;
}

[...snip first example alternative...]

int IsFemale (const edict_t *ent) {
char *info;
return ent->client != NULL
&& (info =
Info_ValueForKey (ent->client->pers.userinfo,
"skin")) != NULL
&& (*info == 'f' || *info == 'F');
}

... but I think this breaches the bounds of good taste.

Promulgating your prejudices?
 
T

Tim Rentsch

This I use a my general style guideline:

When two wordings are equivalent, use the shorter one.

More precise:

When two wordings are equivalent, and there is no other
strong reason to prefer one of them, use the shorter one.

This is a vacuous statement unless some effort is made to
identify which reasons might be sufficiently compelling
to justify a longer wording and which others are not.
 
J

John Gordon

In said:
(e-mail address removed)-berlin.de (Stefan Ram) writes:
This is a vacuous statement unless some effort is made to
identify which reasons might be sufficiently compelling
to justify a longer wording and which others are not.

I disagree. There can be any number of reasons to prefer one equivalent
wording over another, and those reasons can vary wildly depending on
the problem domain.

Just to pick one random example, if you're writing user documentation you
might prefer a passage with a friendly tone versus a shorter one that
contains the same technical content but is terse and unwelcoming.
 

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

No members online now.

Forum statistics

Threads
474,085
Messages
2,570,597
Members
47,218
Latest member
GracieDebo

Latest Threads

Top