From owner-svn-src-all@FreeBSD.ORG Tue Aug 26 18:13:49 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 14761EF; Tue, 26 Aug 2014 18:13:49 +0000 (UTC) Received: from mail110.syd.optusnet.com.au (mail110.syd.optusnet.com.au [211.29.132.97]) by mx1.freebsd.org (Postfix) with ESMTP id B6D7D3608; Tue, 26 Aug 2014 18:13:48 +0000 (UTC) Received: from c122-106-147-133.carlnfd1.nsw.optusnet.com.au (c122-106-147-133.carlnfd1.nsw.optusnet.com.au [122.106.147.133]) by mail110.syd.optusnet.com.au (Postfix) with ESMTPS id 4AE507839FF; Wed, 27 Aug 2014 03:43:19 +1000 (EST) Date: Wed, 27 Aug 2014 03:43:18 +1000 (EST) From: Bruce Evans X-X-Sender: bde@besplex.bde.org To: Benjamin Kaduk Subject: Re: svn commit: r270227 - head/sys/sys In-Reply-To: Message-ID: <20140827015544.C40875@besplex.bde.org> References: <201408201632.s7KGW2vF093636@svn.freebsd.org> <20140826233018.H32188@besplex.bde.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed X-Optus-CM-Score: 0 X-Optus-CM-Analysis: v=2.1 cv=AOuw8Gd4 c=1 sm=1 tr=0 a=7NqvjVvQucbO2RlWB8PEog==:117 a=PO7r1zJSAAAA:8 a=RrlIlrznAvoA:10 a=Bs0Nco5NFfgA:10 a=kj9zAlcOel0A:10 a=JzwRw_2MAAAA:8 a=TF_a1ho2fTJttlButMQA:9 a=CjuIK1q_8ugA:10 Cc: "svn-src-head@freebsd.org" , "svn-src-all@freebsd.org" , "src-committers@freebsd.org" , Bruce Evans X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Aug 2014 18:13:49 -0000 On Tue, 26 Aug 2014, Benjamin Kaduk wrote: > On Tue, Aug 26, 2014 at 9:58 AM, Bruce Evans wrote: > >> >> That would be a further obfuscation. The *INTC() macros expand to >> integer constant expressions of the specified type suitable for use >> in #if preprocessing directives. (It is otherwise difficult to >> detemine the correct suffix, to add to the constant to give it the >> specified type). There are no preprocessing directives here, so a >> simple cast works. The cast could also be applied to the other >> operand but it is easier to read when applied to the constant. > > I thought that in C99, all integers in preprocessor evaluation were treated > as if > they were [u]intmax_t (6.10.1.4 in the n1256.pdf I have here). I was only > just > skimming that part yesterday for unrelated reasons, though, so maybe I'm > missing the bigger picture. Yes, that makes it unclear what typed constants in cpp expressions are useful for. C has always been careful to make limits like UINT_MAX have the correct type, but that seems to be worse than useless in cpp expressions. (Oops. I was thinking that UCHAR_MAX had type u_char, but the correctness actually goes the other way -- it is required to have type the promotion of u_char (signed int except on exotic machines). UINT_MAX has type unsigned int. So -UINT_MAX > 0 in normal expressions. But in cpp expressions, UINT_MAX promotes to intmax_t before it is negated (since C's broken "value-preserving" promotion rules apply). So -UINT_MAX < 0 in cpp expressions. There seem to be some compiler bugs in this. In cpp expressions, testing on clang on amd64 gives -UINT_MAX < 0 and -0xFFFFFFFF < 0, but -0xFFFFFFFFU > 0. The first 2 results are the same since UINT_MAX is just 0xFFFFFFFF. ( intentionally avoids using suffixes on constants if possible since it didn't use them old versions, I don't like them, and I would have tried to undo any changes that added them. Some buggy versions used them to break thinks like USHRT_MAX -- 0xFFFFU has the wrong type.) But 0xFFFFFFFF and 0xFFFFFFFFU have the same type if u_int == uint32_t, since the type of an unsuffixed hex constant is the type of lowest rank that can represent it. gcc-3.3 on i386 under an old version of FreeBSD gives the same results, except UINT_MAX is defined with a U suffix so the the result for it agrees with the wrong result for 0xFFFFFFFF. Perhaps this is specified somewhere, but it is bizarre for 0xFFFFFFFFU to promote not bug for bug compatibly with the "value-preserving" rules, while the same type and value spelled as 0xFFFFFFFF does promote bug for bug compatibly. TenDRA (4.2) is normally more of a C compiler than gcc or clang, and it gives very interesting errors for all 3 cpp expressions: [ISO C90 6.8.1]: Can't have target dependent '#if' at outer level. The expression is target-dependent since the type of 0xFFFFFFFF depends on the size of int. Even the result of -1U > 0 is apparently target- dependent in C90. I think it is still target-dependent. On exotic targets, uintmax_t == u_int, so there is no promotion and -1U > 0, but on normal targets 1U promotes to a (intmax_t)1 and negating that makes it negative. I didn't know about this stupid rule 6.8.1. It mainly prevents you writing target-dependent cpp expressions to determine the target. It seems to be a bug in TenDRA. 6.8.1 only says that it is implementation-defined whether the result is the same as a non-cpp expression, and gives an example of a more usefule expression involving character constants being quite likely to give a different rewsult. Sigh. My compiler and TurboC handled cpp expressions better in 1988. cpp was part of the compiler, so casts, sizeof() and floating point worked in it, and the result of constant expressions didn't depend on whether they were evaluated in cpp. Running my compiler now gives -0xFFFFFFFF > 0 for all spellings of 0xFFFFFFFF, since the compiler is pre-C90 and never implemented "value-preserving" promotion. It also never supported 64-bit integers, so promotion doesn't apply in this example, but it applies to -0xFFFF in 16-bit mode similarly. >> The expression could also be written without a cast and without using >> UINT64_C(), by using a 'ULL' suffix instead of 'LL'. That would still >> use the long long abomination, and be different obfuscation -- the >> type of the constant doesn't really matter, but we need to promote >> to the type of 'frac', that is, uint64_t. 'ULL' works because long >> longs are at least 64 bits (and I think unsigned long longs are also >> 2's complemention, so their type is larger than uint64_t. > > Two's complement semantics are guaranteed for the fixed width types > such as int64_t, but I'm not sure how that comes into play for unsigned > types? Unsigned types have 2's complement arithmetic, but might not have purely 2's complement representations (except for unsigned char). They can have padding bits, Perhaps with trap representations. I think that is the only complication allowed in in C99 and later. In C90, I think the representation could be anything, but C90 only allows 3 types of representations for integer types, and it allows inspecting representations by copying to arrays of unsigned char and looking at the bits. Both long long and unsigned long long are 64 bits, but 64 bits is not quite enough to guarantee representing int64_t since int64_t has a 2's complement while long long might be 1's complement -- then it can't represent INTMAX_MIN. This problem doesn't affect the unsigned case. Bruce