From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1BcnNT-0004rz-7U for qemu-devel@nongnu.org; Tue, 22 Jun 2004 11:40:03 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1BcnNS-0004rU-3j for qemu-devel@nongnu.org; Tue, 22 Jun 2004 11:40:02 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1BcnNR-0004rC-VX for qemu-devel@nongnu.org; Tue, 22 Jun 2004 11:40:01 -0400 Received: from [64.253.108.95] (helo=talon.kainx.org) by monty-python.gnu.org with esmtp (Exim 4.34) id 1BcnLe-0007iD-Gt for qemu-devel@nongnu.org; Tue, 22 Jun 2004 11:38:11 -0400 Date: Tue, 22 Jun 2004 11:38:08 -0400 From: Michael Jennings Subject: Re: [Qemu-devel] Re: completely OT: C Q/As Message-ID: <20040622153808.GV4686@kainx.org> References: <40D6A164.2010109@petig-baender.de> <40D6A164.2010109@petig-baender.de> <20040621154440.GQ4686@kainx.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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/ 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"