ted@blia.UUCP (02/24/87)
We have found a difference between the code generated by DEC VAX C versions 1.5 and 2.1. The C code that compiles to this is incorrect (missing a cast) but none-the-less was in some of our code and the net result was code that worked when compiled by 1.5 and didn't work when compiled by 2.1. I wanted to share this with the net in case there is anyone else who has similar code and will be bitten. If this has been discussed in the past, I apologize for bringing it up again; we just recently found it. The difference occurs when you compare an unsigned short against a negative value without casting the short as a signed short. For example: unsigned short x; subroutine(&x); /* subroutine writes back a value through the ptr */ if (x < -10) /* should read "if (((short) x) < -10)" */ Version 1.5 generates a CVTWL and a CMPL for the if and thus the value in x is sign extended and everything works anyway. Version 2.1 generates a MOVZWL instead of the CVTWL and so it isn't sign extended and the condition is never true. (BTW, the reason this was in the code was that the value could be interpreted as either signed or unsigned depending on other conditions.) Anyway, let this be a warning. If you write improper C code (i.e. it passes the DEC compiler but wouldn't have passed lint) and it works under the current version of the DEC compiler, don't expect it to continue to work under later versions. =============================================================================== Ted Marshall Britton Lee, Inc. p-mail: 14600 Winchester Blvd, Los Gatos, Ca 95030 voice: (408)378-7000 uucp: ...!ucbvax!mtxinu!blia!ted ARPA: mtxinu!blia!ted@Berkeley.EDU disclaimer: These opinions are my own and may not reflect those of my employer; I leave them alone and they leave me alone.
msb@sq.UUCP (03/01/87)
Ted Marshall (ted@blia.BLI.COM) writes: > We have found a difference between the code generated by DEC VAX C versions > 1.5 and 2.1. ... > > The difference occurs when you compare an unsigned short against a negative > value without casting the short as a signed short. For example: > unsigned short x; > subroutine(&x); /* subroutine writes back a value through the ptr */ > if (x < -10) /* should read "if (((short) x) < -10)" */ > Version 1.5 generates a CVTWL and a CMPL for the if and thus the value in > x is sign extended and everything works anyway. Version 2.1 generates a > MOVZWL instead of the CVTWL and so it isn't sign extended and the condition > is never true. Then there was a bug in version 1.5. And you were lucky that the constant was negative -- the bug would presumably still have affected the code if it was positive, but it would have been a lot harder to detect, because the condition would not have been degenerate! The type of -10 is int and the type of x is, of course, unsigned short. By the Oct.1 ANSI draft, we have: 3.3.8: If both of the operands [of <] have arithmetic type, the usual arithmetic conversions are performed. 3.2.1.5 [Usual arithmetic conversions]: [If neither operand has a floating type or type unsigned long int or long int], the integral promotions are performed. 3.2.1.1: In all cases the value is converted to int if an int can represent all values of the original type. [This and certain other conversions] are called the integral promotions. 3.2.1.2: When an unsigned integer is promoted to a longer integer, its value is unchanged. All of which says that x is converted to int and should not be sign extended in doing so. In the days of K&R there were no unsigned shorts, but if you instead consider the combination of an unsigned int with a long (assuming that int is shorter than long), you get the same rule: no sign extension. The text corresponding to the above, with that change, can be found in sections 7.6, 6.6, and 6.5 of Appendix A to K&R. > (BTW, the reason this was in the code was that the value could > be interpreted as either signed or unsigned depending on other conditions.) A safer way to do this, of course, is to declare the type of x as "union {unsigned short un; short si;}". This forces you to say "x.si" or "x.un" each time you use it, and reduces the chance of errors like these. In addition, this improves the portability of the code. The conversion (short)x may do other things besides interpreting the bits in a different fashion; on a machine that, unlike the VAX, isn't of the common 2's complement type, it WILL do other things. Most likely you did just mean to reinterpret the bits, in which case a union is what you really want. Of course, you then have to be careful to ASSIGN the value to x.si in a signed context or x.un in an unsigned context, as well as reading from the right one. Mark Brader, utzoo!sq!msb C unions never strike!