eppstein@garfield.columbia.edu (David Eppstein) (05/24/87)
The following program prints both messages. I would expect it to print
neither, but at least the second message shouldn't happen. The
generated C code for the two lines is essentially identical; no doubt
the second line and probably the first should have generated a cast to int.
This is on a Vax running 4.3; I don't know what version C++.
It occurred in a real example and took me much grief to track down.
I'm not convinced the C compiler is correct, which is why I'm also cross
posting to comp.lang.c.
------------
#include <stream.h>
int a = -1;
unsigned b = 2;
inline int conv() { return b; }
main()
{
if (a > b) cout << "(int) -1 > (unsigned) 2 ???\n";
if (a > conv()) cout << "(int) -1 > (int) (unsigned) 2 ????????\n";
}
--
David Eppstein, eppstein@cs.columbia.edu, Columbia U. Computer Science Dept.
donn@utah-cs.UUCP (05/28/87)
David Eppstein says that he expects no output from the following program: ------------------------------------------------------------------------ #include <stream.h> int a = -1; unsigned b = 2; inline int conv() { return b; } main() { if (a > b) cout << "(int) -1 > (unsigned) 2 ???\n"; if (a > conv()) cout << "(int) -1 > (int) (unsigned) 2 ????????\n"; } ------------------------------------------------------------------------ I believe both C and C++ apply the same rules for automatic conversions in this example. The first test 'a > b' should produce 1 since 'a' is converted to unsigned and on a two's complement machine, '(unsigned) -1' is the largest unsigned integer. In the second test 'a > conv()', both operands are signed integers and hence the comparison is a signed comparison and the result is 0. C++ 1.2.1 cfront fails to generate a C cast to coerce the type of the return value of conv() to int; the C++ reference manual (r.8.1) guarantees that an inline function has the same result as a call to a real function, rather than a call to a macro, so C++ 1.2.1 is wrong. (This reminds me of some bugs with Fortran statement functions and the 4.2 BSD f77 compiler...) It is probably useful to note here that the 4.3 BSD C compiler is an 'unsigned preserving' compiler in the terms of ANSI C -- unsigned char and unsigned short promote to unsigned int in implicit conversions. C++ is explicitly 'value preserving' -- small unsigned types promote to int (r.6.6, except unsigned short conversion is not treated; in any case a qualification about unsigned short on machines where sizeof (unsigned short) == sizeof (int) is needed). Since C++ 1.2.1 cfront makes no effort to force its 'value preserving' practice on 'unsigned preserving' Unix C compilers, it is thus the case that on Unix machines, C++ is also 'unsigned preserving'. Donn Seeley University of Utah CS Dept donn@cs.utah.edu 40 46' 6"N 111 50' 34"W (801) 581-5668 utah-cs!donn PS -- Personal opinion: the argument for 'value preserving' promotion is that it is less confusing -- it is somehow safer for the novice to be able to write: int i = -1; unsigned char uc = 2; unsigned int ui = 2; if (uc > i) printf("ANSI\n"); if (ui < i) printf("ANSI too\n"); I fail to see how this is less confusing... PPS -- C++ 1.2.1 cfront botches certain constant comparisons between int and unsigned; for example, the following program prints 'wrong': ------------------------------------------------------------------------ #include <stream.h> int main() { if ((unsigned) 2 > -1) cout << "wrong\n"; return 1; } ------------------------------------------------------------------------ If the cast is moved to the right operand of > in the example, C++ 1.2.1 cfront simply punts on the constant folding and lets the C compiler handle it.
msb@sq.UUCP (05/29/87)
Donn Seeley (donn@utah-cs.UUCP) writes: > ... on a two's complement machine, '(unsigned) -1' > is the largest unsigned integer. Actually, (unsigned) -1 should be the largest unsigned int on ANY machine. K&R Appendix A ref: section 6.5 on page 184 ANSI Oct.1 draft ref: section 3.2.1.2 on page 28 What IS true only on a 2's complement machine is that converting a negative number to unsigned does not change the bit pattern. Mark Brader, SoftQuad Inc., Toronto, utzoo!sq!msb #define MSB(type) (~(((unsigned type)-1)>>1))
bs@alice.UUCP (06/08/87)
> From: eppstein@garfield.columbia.edu.UUCP (eppstein @ Columbia University CS Department) > The following program prints both messages. I would expect it to print > neither, but at least the second message shouldn't happen. The > generated C code for the two lines is essentially identical; no doubt > the second line and probably the first should have generated a cast to int. > > #include <stream.h> > > int a = -1; > unsigned b = 2; > > inline int conv() { return b; } > > main() > { > if (a > b) cout << "(int) -1 > (unsigned) 2 ???\n"; > if (a > conv()) cout << "(int) -1 > (int) (unsigned) 2 ????????\n"; > } It is clearly a cfront bug that ``conv()'' is expanded into ``b'' and not ``(int)b''. Sorry. For people with release 1.2 here is a fix (a new ck_cast() for expand.c): int ck_cast(Ptype t1, Ptype t2) /* return a value of type t2 from a function returning a t1 return 1 if cast is needed */ { while (t1->base == TYPE) t1 = Pbase(t1)->b_name->tp; while (t2->base == TYPE) t2 = Pbase(t2)->b_name->tp; if (t1 == t2) return 0; if (t1->base != t2->base) return 1; switch (t1->base) { case CHAR: case SHORT: case INT: case LONG: if (Pbase(t1)->b_unsigned != Pbase(t2)->b_unsigned) return 1; } if (t1->base == COBJ) { Pname nn = Pbase(t1)->b_name; if (Pclass(nn->tp)->csu==UNION ) return 0; if (t2->base==COBJ && nn->tp==Pbase(t2)->b_name->tp) return 0; return 1; } return 0; } I'll leave the question of the correct value of ``a>b'' to your local C compiler until the ANSI C standard finally appears. Interestingly enough my C compiler causes this program main() { int a = -1; unsigned b = 2; if (-1>(unsigned)2) printf("true\n"); else printf("false\n"); if (a>b) printf("true\n"); else printf("false\n"); } so that it produces false true which is clearly a bug.
mar@hpclla.UUCP (06/09/87)
>/ hpclla:comp.lang.c / eppstein@garfield.columbia.edu (David Eppstein) / 12:39 pm May 24, 1987 / > The following program prints both messages. I would expect it to print > neither, but at least the second message shouldn't happen. The > generated C code for the two lines is essentially identical; no doubt > the second line and probably the first should have generated a cast to int. > This is on a Vax running 4.3; I don't know what version C++. > It occurred in a real example and took me much grief to track down. > I'm not convinced the C compiler is correct, which is why I'm also cross > posting to comp.lang.c. > #include <stream.h> > int a = -1; > unsigned b = 2; > inline int conv() { return b; } > main() > { > if (a > b) cout << "(int) -1 > (unsigned) 2 ???\n"; > if (a > conv()) cout << "(int) -1 > (int) (unsigned) 2 ????????\n"; > } I compiled this using the 1.1 version of C++. The C code generated is incorrect, you were right in assuming that the C++ compiler should generate a cast to int for the inline construct. The C compiler is correct in how the code is handled. By ordinary promotion rules, if one operand is unsigned then the other is converted to unsigned and the expression result is unsigned. Hence, in the expression 'a' is converted to unsigned before the comparison and the result is true: ( (unsigned) -1 > (unsigned) 2. The C code generated for the second expression is identical except for an extra set of parens around the return value 'b', which are insignificant in this case, so the evaluation is the same as above:. (unsigned) -1 > (unsigned) 2. Michelle Ruscetta (hplabs!hpda!mar)