rns@se-sd.sandiego.ncr.com (Rick Schubert) (08/31/88)
I believe I have found a bug in a C compiler I am using, but I cannot find anything in K&R I or the Draft ANSI Standard that <<directly>> addresses the issue. The compiler in question is pre-draft-ANSI, but I frequently look at the Draft in such situations where only K&R I features are involved. Anyway, the situation involves parameters of type `char'. Remember that this is pre-draft-ANSI, so that function prototypes do not exist. If I define a function `f' as follows: f(c) char c; { ... } the compiler in question gives a warning that type type of `c' is being changed to `int'. I could not find anything in K&R I or the Draft that addresses such parameters. The closest I could find is in K&R I section 2.7 (page 42): Since a function argument is an expression, type conversions also take place when arguments are passed to functions: in particular, `char' and `short' become `int', and `float' becomes `double'. This is why we have declared function arguments to be `int' and `double' even when the function is called with `char' and `float'. I was aware of what happens to the <<argument>>. The passage does not explain, however, what happens when one declares the parameter to be type `char' or `float'; I don't see this prohibited anywhere. To continue: when I first saw the warning from the compiler, I thought that the warning was invalid, since I thought that it was okay to declare such a parameter. I knew about the treatment of function <<arguments>>, but I felt that, as long as the compiler generated code to reference the correct byte of the `int', that things would work out (this is what other compilers I have used have done). I even thought that it would be safe to ignore the warning, since, in most contexts, treating the parameter as an `int' or a `char' would not make any difference: in an expression, the `char' would be promoted to an `int'; on assignment, an `int' would be properly truncated to a `char'. The problem comes in taking the address of the parameter. Ignoring the problem that `&c' would produce an `int *' rather than a `char *', which byte does `&c' point to? The programmer who wrote `char c' would expect it to point to the byte containing the character that was passed to the function; i.e., in the following example: . . . f('A'); . . . f(c) char c; { g(&c); } g(p) char *p; { char c2; c2 = *p; } the programmer would expect `p' to point to a byte containing 'A', so that `c2' would be assigned 'A'. With the compiler in question, however, `p' points to the high-order byte of a word whose low-order byte is 'A', i.e. the word contains the value 0x00000041, and `p' points to 0x00 rather than 0x41, so that `c2' gets assigned 0x00 or '\0'. My questions are: 1. Is it illegal to declare a parameter to be of type `char'? 2. If not, is it valid to treat the parameter as type `int'? 3. If so, what does the unary `&' operator do to such a variable? 4. Where is this addressed in K&R I? 5. Where is this addressed in the Draft (assuming no prototypes)? Thanks for any useful information. -- Rick Schubert (rns@se-sd.sandiego.NCR.COM)
gwyn@smoke.ARPA (Doug Gwyn ) (09/01/88)
In article <1616@se-sd.sandiego.ncr.com> rns@se-sd.sandiego.NCR.COM (Rick Schubert) writes: > 1. Is it illegal to declare a parameter to be of type `char'? No, but it's rather pointless since the parameter really IS passed as an int. The compiler HAS to make the adjustment. > 2. If not, is it valid to treat the parameter as type `int'? This is recommended practice. > 3. If so, what does the unary `&' operator do to such a variable? Takes its address, just as for any other int.
swilson%thetone@Sun.COM (Scott Wilson) (09/01/88)
>I was aware of what happens to the <<argument>>. >The passage does not explain, however, what happens when one declares the >parameter to be type `char' or `float'; I don't see this prohibited >anywhere. I was bitten by the float/double version of this once. I had declared a formal parameter as a float, took its address and passed what I thought was a float pointer to another function. Anyway, I don't have K&R 2nd edition around, but K&R 1st edition does describe float formal arguments. From page 205: C converts all float actual parameters to double, so formal parameters declared float have their declaration adjusted to read double. Your're right though, that int vs. char is not explicitly mentioned in this section. -- Scott Wilson arpa: swilson@sun.com Sun Microsystems uucp: ...!sun!swilson Mt. View, CA
bgibbons@Apple.COM (Bill Gibbons) (09/01/88)
In article <1616@se-sd.sandiego.ncr.com> rns@se-sd.sandiego.NCR.COM (Rick Schubert) writes: >I believe I have found a bug in a C compiler I am using ... >If I define a function `f' as follows: > f(c) > char c; > { > ... > } > >the compiler in question gives a warning that type type of `c' is >being changed to `int'. > ... In section 3.7.1 of the draft standard, it says: On entry to the function the value of each argument expression shall be converted to the type of its corresponding parameter, as if by assignment to the parameter. This is known as _narrowing_. It is very important, for exactly the reason you point out: if the parameter is not narrowed, and you take its address, the pointer is to a different type than expected. Narrowing is very easy for a compiler to do: for CHAR and SHORT, it just adjusts the stack offset at which it thinks the value was passed, and changes the type. (On PDP11 etc, it doesnt even change the offset.) Floating-point is a little harder on most machines; it needs an explicit conversion. This caused me a lot of effort last fall, when I was porting a UNIX application to IDRIS running on an Atari box. The Whitesmiths compiler did not do narrowing, and I had to modify the code (with a tool) to add explicit narrowing. Without a tool to systematically change the code, it would have been hopeless. (After I got it working and it showed at Comdex, Atari cancelled the product. Fortunately, someone else was paying :-) Bill Gibbons (contractor) bgibbons@apple.com