[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #9 from roberto dot gordo at gmail dot com 2007-03-17 17:58 --- I would like to apologize for my faults in gcc bug report 31166, specially to the people who responded, and fully acknowledge my error. I've misunderstood your responses. Now, while reading them again, they appear completely logical to me. I was working during hours with a piece of code on which I've been bitten by lots of c language weirdness. I've discovered and fixed most of them (except the reported one), but after so many consecutive hours of debugging such ugly code my mind was not in a very clear state... and my comments were fairly stupid, I must admit. I'm sorry for that. There is still something remaining that I don't fully understand (the integer/unsigned promotion thing). I'm still wondering about that, but I accept your responses, so I think I'm somewhat not giving the right interpretation at the standard wordings. I will try to find the cause on mailing lists or other places, since the gcc bugzilla may not be the correct place. Thanks for your patience and please accept my apologies for wasting your time. Sorry. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #5 from roberto dot gordo at gmail dot com 2007-03-14 08:52 --- unsigned is never promoted, it always stays unsigned. Sorry to insist, but I'm still not convinced. Please, see these examples, compiled with -std=c99. { unsigned u; int i; u = 1; /* this is an unsigned */ i = -u; /* this is an unsigned turned into a negative int */ printf(%d\n, i); /* It will print -1 */ } Another example. { long long ll; ll = -2147483648; printf(%lld\n, ll); /* It will print -2147483648 */ } 2147483648 is the same constant as 0x8000. Acording to your comments, this is an unsigned, because it does not fit on an int, and it should remain as unsigned. But it is not. There is not overflow in printf, because I print as long long. This is just the same example, because 2147483648 == 0x8000 { long long ll; ll = -0x8000; printf(%lld\n, ll); /* It will print 2147483648 */ } It is the same constant, represented on hex. Just the same number. I'm reading the ISO C standard right now, and I can't find any explanation for an hex constant to have such different semantics. If there it is and I've missed it, I would appreciate to be pointed to the section of the standard which explains this behavior, please. -- roberto dot gordo at gmail dot com changed: What|Removed |Added Status|RESOLVED|UNCONFIRMED Resolution|INVALID | http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #6 from roberto dot gordo at gmail dot com 2007-03-14 09:27 --- I think I've found something. According to the ISO C standard, a decimal constant without suffixes should ALWAYS be signed int (or signed long long if it does not fit), but never be unsigned! An octal or hexadecimal constant without suffixes may be unsigned when it does not fit on a signed. I was not aware of this, sorry (and according to your comments, I think neither you were, because the explanations that you gave to my bug report were not true). -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #7 from roberto dot gordo at gmail dot com 2007-03-14 09:40 --- That's OK, it is not a bug, sorry. -- roberto dot gordo at gmail dot com changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution||INVALID http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #8 from roberto dot gordo at gmail dot com 2007-03-14 12:29 --- I'm still unable to match the behavior of gcc with the ISO C standard. I will try to explain myself. The reason for which gcc produces different results with hex constants is now clear. Also, in the following quotation: The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type. I acknowledge that I've failed to note that given this code long long ll; ll = -0x8000; the operand for the unary - operator is promoted first, and the operation is done next. The result may fit on an int, but according to the standard, the result has the promoted type (which has been already calculated as unsigned). BUT.. you said Integer promotion is only performed on types smaller than int. and I would want to comment on this. I do not claim to have good understanding of English, so I may be interpreting the ISO C standard on a wrong way. Before reopening the bug, I would appreciate comments on this. This are the relevant parts: Section: Conversions - Arithmetic operands - Boolean, characters, and integers The following may be used in an expression wherever an int or unsigned int may be used: - An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int. [...] If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. Please, note the wording: less than *or equal*. As I read it, I understand that promotion rules are applied to int, unsigned int, or other types with less rank. And any unsigned int small enough to fit on a signed int is converted. These rules appears to be valid also for the unary - , and even when operator is unsigned. I would be happy to change my mind if you point to any section of the standard stating that unsigned operands should never be touched, but currently the text I see appears to say the opposite. So, in the way I view it, the expression: -10U should return an int instead of unsigned, and it should be safe to assign it to a bigger integer. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #1 from schwab at suse dot de 2007-03-13 20:22 --- 0x8000 is of type unsigned int, negating it gives an unsigned int of the same value, converted to long long still gives the same positive value. On the other hand 2147483648 is of type long long (in C99) because it does not fit in long, and gives -2147483648 as long long when negated. C90 does not have long long, so 2147483648 is undefined behaviour, and GCC chooses unsigned long since it fits there. -- schwab at suse dot de changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution||INVALID http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #2 from roberto dot gordo at gmail dot com 2007-03-13 22:27 --- I do not agree at all. Please, read. So 0x8000 is unsigned because does not fit on an int type. That's OK. If negating it gives an unsigned int of the same value, then, how do you explain that the following code prints n1 = -2147483648 int n1; n1 = -0x8000; printf(n1 = %d\n, n1); It works because the expression should not be unsigned. This is a quotation from ISO/IEC 9899:1999 standard: The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type. and... Several operators convert operand values from one type to another automatically [...] If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. The unary - operator can (and should) apply again the promotion rules, and should choose int. So the expression -0x8000 shall promote to a signed integer type in which it fits, which happens to be an int (on c99 and c90). And as you can see, gcc works correcly here, just as the standard says. But if fails when the lvalue is long long instead of int, as here: long long n1; n1 = -0x8000; In case we have an int expression at the right, it should be converted as long long without problems. In case we have a long long at the right, it should also work without problems (at least for c99). And if we have an unsigned int at the right, as you said, it should have not worked with an int and it is a bug by itself in the way I understand the standard. -- roberto dot gordo at gmail dot com changed: What|Removed |Added CC||roberto dot gordo at gmail ||dot com Status|RESOLVED|UNCONFIRMED Resolution|INVALID | http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #3 from schwab at suse dot de 2007-03-13 22:35 --- (In reply to comment #2) So 0x8000 is unsigned because does not fit on an int type. That's OK. If negating it gives an unsigned int of the same value, then, how do you explain that the following code prints n1 = -2147483648 You print it as a signed integer. It works because the expression should not be unsigned. The value is converted to signed int by printf. The unary - operator can (and should) apply again the promotion rules, and should choose int. Integer promotion is only performed on types smaller than int. The unary - operator can (and should) apply again the promotion rules, and should choose int. The operand is unsigned int, so there is no promotion. -- schwab at suse dot de changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution||INVALID http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166
[Bug c/31166] Integer hex constant does not follow promoting rules
--- Comment #4 from pinskia at gcc dot gnu dot org 2007-03-13 22:35 --- unsigned is never promoted, it always stays unsigned. So -0x8000 == 0x8000 :). Try adding ULL (or UL) if you want an unsigned long long (unsigned long) constant. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166