Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!ccu.umanitoba.ca!herald.usask.ca!alberta!ubc-cs!van-bc!zaphod.mps.ohio-state.edu!think.com!snorkelwacker.mit.edu!bloom-picayune.mit.edu!news From: scs@adam.mit.edu (Steve Summit) Newsgroups: comp.std.c Subject: Re: Strange behaviour with old-style code Message-ID: <1991Feb9.084829.28613@athena.mit.edu> Date: 9 Feb 91 08:48:29 GMT References: <1991Feb6.190607.11731@alias.uucp> Sender: news@athena.mit.edu (News system) Reply-To: scs@adam.mit.edu Organization: Thermal Technologies, Inc. Lines: 86 In article <1991Feb6.190607.11731@alias.uucp> rsargent@alias.UUCP (Richard Sargent) writes: >I have come across a compiler which does something very unusual >in its handling of old-style functions. >The compiler passes floats widened to doubles, and the routine pulls >the values off the stack using the appropriate widened addressing, >but then proceeds to use the "declared" argument type to do single >precision floating point arithmetic. Actually, it looks like the compiler is behaving correctly. If you thought that the compiler should treat bar(u) float u; { ... "as if" u had been declared as a double, that is exactly what the compiler is _not_ supposed to do. The compiler is instead supposed to do the equivalent of bar($u) double $u; { float u = $u; ... where $u is just a pseudo-name for the passed value, on the stack or wherever. As you may have suspected, the distinction is significant if the address of u is passed to some other routine which expects a pointer-to-float. > A colleague of mine has > crawled through the Standard as well as K&R II, but found nothing > that explicitly addresses this issue. X3.159, section 3.7.1, p. 82, lines 21-22: "On entry to the function the value of each argument shall be converted to the type of its corresponding parameter, as if by assignment to the parameter." The Rationale reasserts this, and explicitly states that "Type rewriting [i.e. pretending that float arguments had been declared double] is no longer permissible." K&R2 spells this out in some fine print in section A10.1, on page 226: "There is... a small change in the details of promotion: the first edition specified that the declarations of float parameters were adjusted to read double. The difference becomes noticeable when a pointer to a parameter is generated within a function." The distinction is actually between the old interpretation of old-style function definitions and the new interpretation of those old definitions. Your compiler appears to be correctly following the new interpretation. (I say "appears" because it correctly reports sizeof(u) as 4. There is a subtle, secondary bug which is possible, depending on the machine's floating-point formats. Given a fortuitous byte order and bit arrangement, it is often possible, or at least appears possible, essentially to skip the local allocation and assignment float u = $u; and generate code which treats the stack location $u as if it were a float. This works if the bits and bytes making up a float are an initial subset of those making up a double, with the added bits in a double simply adding precision. For example, VAX F_ and D_floating formats satisfy this relationship. However, the Rationale warns that "Not many implementations can subset the bytes of a double to get a float. Even those that apparently permit simple truncation often get the wrong answer on certain negative numbers." I am sure that someone else will expand on this point if it is important.) Note, by way of contrast, that since "Array expressions and function designators as arguments are converted to pointers before the call," it _is_ the case that "A declaration of a parameter as `array of type' shall be adjusted to `pointer to type,' and a declaration of a parameter as `function returning type' shall be adjusted to `pointer to function returning type'". (X3.159 section 3.7.1 again.) That is, float (and char and short) parameter declarations are not "rewritten," while array and pointer parameters are. Steve Summit scs@adam.mit.edu