qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] Re: completely OT: C Q/As


From: Michael Jennings
Subject: Re: [Qemu-devel] Re: completely OT: C Q/As
Date: Tue, 22 Jun 2004 11:38:08 -0400
User-agent: Mutt/1.4.2.1i

On Tuesday, 22 June 2004, at 11:57:23 (+0200),
Charlie Gordon wrote:

> This is a common misunderstanding.  your last statement doesn't make
> sense : in C, false IS 0 and true IS 1.  That is the result of a
> false comparison is 0 (eg: 2 == 3) and the result of a true
> comparison is 1 (as in 2 == 2).  As such boolean expressions can
> only have 2 values : 0 and 1, appropriately defined as FALSE and
> TRUE, be it via #define or enum.

Incorrect.  The result of a boolean operator is guaranteed to be 1 or
0.  However, values evaluated in a boolean context such as those in an
if statement are not bound by that rule.

> Unlike its distant cousin Java, C allows non boolean expressions to
> control test statements such as 'if', 'for', and 'while'.  In such
> constructs, falseness is not limited to the integer value 0 : '\0',
> 0.0, and NULL pointers also convert to false, while all other values
> convert to true.

All the values you mentioned evaluate to (int) 0 in a boolean context.

> Further confusion is caused by the convention used in the standard C
> library where boolean valued function do not necessarily return 1
> for trueness.

As there is no such thing as a "boolean value" in C, no standard C
function returns a boolean value.  Some do, however, return an integer
that may be successfully used in a boolean context (albeit possibly
negated).

> I do agree with you that there is room for confusion, especially for
> java bred programmers, and it is usually better to avoid the extra
> clutter of comparing to FALSE or TRUE in test expressions : just use
> the plain expression or bang (!) it for the reverse condition.

That was not my statement.  Again, it depends on what you're doing.
If you're guaranteed a return of 0 or non-zero, best to use == 0 or !=
0.  With pointers, the value itself is fine, negated or not, but other
valid approaches include == NULL, != NULL, or even a macro like
ISNULL().

> These are obvious solutions to the problem, the latter (buffer and
> size) is actually the one used in the C library for that very
> function (itoa).  But the question was a different one : Why does
> this crash later (if you are lucky) ?

You found my answer to be obvious.  I found the question to be
obvious.  So we're even. :-)

The answer you were looking for (regarding the stack) had already been
given.  I was simply taking a different tack.

> You use #if 0 yourself, try pretending you never switch those to #if 1 ?

In production-quality code?  Never.  For testing purposes where only I
was meant to see it?  Absolutely.

> I used to be harsh like this and show contempt for imperfect
> programming.  I've had to grow more tolerant, as 99% of C or C++
> code is indeed imperfect, and most programmers are more focussed on
> problem solving than clean coding.

And a lackadaisical attitude such as this is why so many programmers
just don't know any better.  Be tolerant in what you accept, but
strict in what you create.  And just because something doesn't
generate an error doesn't mean it shouldn't generate a warning.

> The truth is that *anyone* who writes C code is just asking for
> trouble.

Don't agree there.

> after all, it is an accepted convention that all uppercase
> identifiers be preprocessor defined.

We agree on that point at least. :-)

> Christof Petig provided a more compelling example :
> 
> #define USE_MORE_CAUTION  TRUE
> #if USE_MORE_CAUTION == TRUE
>     // this code would compile
> #endif
> #if USE_MORE_CAUTION == FALSE
>     // this code would compile as well
> #endif

Again, it's more properly written as "#if USE_MORE_CAUTION" or "#if
!USE_MORE_CAUTION"

> My point is that if you define TRUE and FALSE in a header file, your
> job is to make sure that you are not setting up boobytraps for the
> unsuspecting (and imperfect) programmer to trigger.

And again, I disagree.  By defining something in a header file that
other programmers will use, you're defining an API.  What is most
important is that it is clear and consistent, not that it follows any
one particular religion.

> I took a look at libast and you DO redefine TRUE and FALSE so as to
> setup such a trap !!! have pity on your users!
> 
> /* from libast/types.h */
> ...
> #undef false
> #undef False
> #undef FALSE
> #undef true
> #undef True
> #undef TRUE
> 
> typedef enum {
> #ifndef __cplusplus
>   false = 0,
> #endif
>   False = 0,
>   FALSE = 0,
> #ifndef __cplusplus
>   true = 1,
> #endif
>   True = 1,
>   TRUE = 1
> } spif_bool_t;
> ...

First off, I'm creating a well-defined API.  I use an enum to create
an actual type I can return, manipulate, check against, blah blah
blah.  I undefine those macros to prevent situations where some
platforms may expand one or more of the LHS values to something that's
no longer valid for the enum while others may not.

Secondly, libast headers are API headers, and are really not all that
different from system headers.  If a programmer wishes to use them,
(s)he should #include them BEFORE any custom headers (s)he may also be
using.  Nothing is stopping a programmer from redefining those macros
as (s)he sees fit.  But for my purposes, the correct choice is clear.

Besides, several other items which are more intended for preprocessor
use (e.g., FIXME_BLOCK and UNUSED_BLOCK) are defined separately.

> While your code is amazingly consistent and readable (except for
> line length),

LOL  You've got me there; I use GNU Emacs under X11, so my maximum
line length is largely dependent on how big the Emacs window was in
which I wrote that code. :-)

Wrapping code at 80 chars can result in some really ugly messes, so I
gave up on that.  I just haven't found a really good alternative yet.

> you can learn from this very thread and fix it : you use strncpy 10
> times. 7 of those are incorrect and at least 5 will lead to
> potential buffer overflow and inefficiencies,

My analysis of the code disagrees, but I'd like to look at any
evidence you may have.

> the remaining 3 could be replaced directly with calls to memcpy.
> You make one incorrect use of strncat, that may overflow by just one
> byte.

You're right, thanks.

Michael

-- 
Michael Jennings (a.k.a. KainX)  http://www.kainx.org/  <address@hidden>
n + 1, Inc., http://www.nplus1.net/       Author, Eterm (www.eterm.org)
-----------------------------------------------------------------------
 "Did you really have to die for me?  All I am for all You are because
  What I need and what I believe are worlds apart."
                                       -- Jars of Clay, "Worlds Apart"




reply via email to

[Prev in Thread] Current Thread [Next in Thread]