[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 #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 #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 #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 #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 #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] New: Integer hex constant does not follow promoting rules
Forgive me if this is reported/fixed already; after many consecutive hours of debugging I currently do not have the courage to search through the list of bugs. Please, try this code (tested on 32bit GNU/Linux), compiled with: gcc -std=c99 -Wall -Wextra -o wtf wtf.c #include int main(void) { int n1, n2; long long n3, n4; n1 = -0x8000; n2 = -2147483648; n3 = -0x8000; n4 = -2147483648; printf("n1 = %d\n", n1); printf("n2 = %d\n", n2); printf("n3 = %lld\n", n3); printf("n4 = %lld\n", n4); return 0; } It consists of two int variables and two long long variables, all of them set to the same value (-2147483648 == 0x8000). This is what I get: n1 = -2147483648 n2 = -2147483648 n3 = 2147483648 n4 = -2147483648 What happened to n3? It appears that hex constants are not promoted to long long the same way as decimal ones. AFAIK, this behavoir does not match C99 (neither C90). When compiling without -std=c99, gcc gives this warning: warning: this decimal constant is unsigned only in ISO C90 I think that gcc is trying to say that the constant does not fit on an int (nor a long) and it is promoted to unsigned, as it is stated by ISO C90. But yes, it should fit on an int, because -2147483648 >= INT_MIN in this architecture. Anyway, it is even more funny, because the warning is only for n2 and n4 (decimal constants) but not for n1 nor n4 (hex constants). This is the output without -std=c99: n1 = -2147483648 n2 = -2147483648 n3 = 2147483648 n4 = 2147483648 Tested with these versions of gcc: Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --with-tune=i686 --enable-checking=release i486-linux-gnu Thread model: posix gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21) Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu Thread model: posix gcc version 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5) Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --enable-languages=c,c++,java,f95,objc,ada,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.0 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-java-awt=gtk-default --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-4.0-1.4.2.0/jre --enable-mpfr --disable-werror --with-tune=pentium4 --enable-checking=release i486-linux-gnu Thread model: posix gcc version 4.0.3 (Ubuntu 4.0.3-1ubuntu5) -- Summary: Integer hex constant does not follow promoting rules Product: gcc Version: 4.1.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: roberto dot gordo at gmail dot com http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31166