From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1Bci17-0000UX-2v for qemu-devel@nongnu.org; Tue, 22 Jun 2004 05:56:37 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1Bci16-0000UK-9I for qemu-devel@nongnu.org; Tue, 22 Jun 2004 05:56:36 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1Bci16-0000UA-7O for qemu-devel@nongnu.org; Tue, 22 Jun 2004 05:56:36 -0400 Received: from [80.91.224.249] (helo=main.gmane.org) by monty-python.gnu.org with esmtp (Exim 4.34) id 1Bchzf-0006tA-Kn for qemu-devel@nongnu.org; Tue, 22 Jun 2004 05:55:08 -0400 Received: from list by main.gmane.org with local (Exim 3.35 #1 (Debian)) id 1Bchze-0001d4-00 for ; Tue, 22 Jun 2004 11:55:06 +0200 Received: from dyn-83-157-75-68.ppp.tiscali.fr ([83.157.75.68]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Tue, 22 Jun 2004 11:55:06 +0200 Received: from gmane by dyn-83-157-75-68.ppp.tiscali.fr with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Tue, 22 Jun 2004 11:55:06 +0200 From: "Charlie Gordon" Date: Tue, 22 Jun 2004 11:57:23 +0200 Message-ID: References: <40D6A164.2010109@petig-baender.de> <20040620192652.GA1927@sentinelchicken.org> <40D6A164.2010109@petig-baender.de> <20040621154440.GQ4686@kainx.org> Sender: news Subject: [Qemu-devel] Re: completely OT: C Q/As, was Re: security_20040618 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 "Michael Jennings" wrote in message news:20040621154440.GQ4686@kainx.org... > There are two problems with using enum's and/or #define's for > TRUE/FALSE. They should not be used in boolean expressions except > where the return value is of that same typedef (e.g., the function > returns bool) or is generated from the same set of #define's. While > false is always 0, true is not always 1. True is non-zero. 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. 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. Further confusion is caused by the convention used in the standard C library where boolean valued function do not necessarily return 1 for trueness. Furthermore, it is perfectly OK to compare values from different typedefs but identical implementation types. 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. > Forgot "static" before char x[20];, or to be more threadsafe, either > malloc() or pass in a buffer and max size. 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) ? > > defensive programming would require that TRUE be also defined as > > > > #define TRUE 1 > > > > as many unsuspecting programmers will expect TRUE and FALSE to be handled in > > the preprocessor phase eg: > > > > #if TRUE > > ... > > somecode(); > > ... > > #endif > > I disagree strongly. Anyone who writes "#if TRUE" or "#if FALSE" is > just asking for trouble; (s)he needs to be taught a lesson. "#if 0" > and "#if 1" are just as obvious, and both "#if 1" and "#if TRUE" are > equally ridiculous. You use #if 0 yourself, try pretending you never switch those to #if 1 ? 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. The truth is that *anyone* who writes C code is just asking for trouble. Yet this is still my favorite language. I do use #if 0 or #if 1 sometimes, never #if TRUE or #if FALSE, but I do not believe people that do should be taught such a difficult lesson : after all, it is an accepted convention that all uppercase identifiers be preprocessor defined. 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 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. 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; ... While your code is amazingly consistent and readable (except for line length), 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, 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. pstrcpy provides the very semantics you require in most of these cases. Cheers, Chqrlie.