I have been reading through the C++ standard and I am surprised to see that users ought to make sure that integer literals never overflow, before compiling their program, as an integer literal overflow results in undefined behavior !
On the other hand, the size of a long int is supposed to be just possibly larger than an int, which in turn is meant to be the native size supported by the underlaying hardware.
In other words, you do not really know the size of a long it, but if some literal overflows it, BOOM !
Boy this looks so primitive to me ! And to defy reason even more, if the integer literal is an unsigned and/or long integer literal, than everything is fine and back to normal: implementations are required to diagnose the problem ! So:
long maxsize1 = max( 0, 5098856789 ); // BOOM !!!
long maxsize2 = max( 0, 5098856789L ); // just fine, compile error
long maxsize3 = max( 0, 5098856789u ); // also fine, compile error
Is there a reason for the undefined behavior ? Is this still up-to-date in the current language ? Could it be fixed for a diagnostic to be required in all possible cases ?
This UB would force all applications to either:
- always use unsigned or long integer literals, which are safe
- statically check for the sizeof (long int) or the LONG_MAX at
the beginning of a translation unit
in order to avoid the UB.
Thank you,
Timothy Madden
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
No. "A program is ill-formed if one of its translation units contains
an integer literal that cannot be represented by any of the allowed
types.": [lex.icons]p3, exact section varies by standard but this text
is the same in C++98 and C++0X. C++0X n3092 is publicly available, as
is the draft immediately before C++98.
This is defined behavior: the implementation must diagnose the error.
> On the other hand, the size of a long int is supposed to be just possibly larger than an int, which in turn is meant to be the native size supported by the underlaying hardware.
>
> In other words, you do not really know the size of a long it, but if some literal overflows it, BOOM !
>
> Boy this looks so primitive to me ! And to defy reason even more, if the integer literal is an unsigned and/or long integer literal, than everything is fine and back to normal: implementations are required to diagnose the problem ! So:
Consider an implementation targeting DOS: 16-bit short, 16-bit int, 32-
bit long, and C99/C++0X wanna-be compilers use 64-bit long long.
Assume pure C90/C++98 compilers do not have long long.
> long maxsize1 = max( 0, 5098856789 ); // BOOM !!!
Syntax error for pure C90/C++98. C99/C++0X compiles (the literal
promotes to long long), but invokes undefined behavior from the
downcast of long long to long. Presumably legal when targeting PDP-11
(36-bit hardware char so int has at least 36 bits!).
> long maxsize2 = max( 0, 5098856789L ); // just fine, compile error
Same as above.
> long maxsize3 = max( 0, 5098856789u ); // also fine, compile error
Syntax error for pure C90/C++98 (we don't get the modulo break). C99/C
++0X compiles (the literal promotes to unsigned long long), but
invokes undefined behavior from the downcast of unsigned long long to
long.
> .... Is this still up-to-date in the current language ?
The citation I mentioned should be current when C++0X becomes a
standard. I haven't verified C++03, but it seems unlikely that it
would be different from both C++98 and C++0X.
> Could it be fixed for a diagnostic to be required in all possible cases ?
No way to fix what isn't broken.
> This UB would force all applications to either:
> ....
> - statically check for the sizeof (long int) or the LONG_MAX at
> the beginning of a translation unit
> in order to avoid the UB.
Frankly, this sort of checking is already needed to avoid undefined
behavior for compile-time signed arithmetic. [Note that the
preprocessor can check based on LONG_MAX, LLONG_MAX, and its relatives
directly. Detecting padding bits is tricky at the moment. (That is,
sizeof(long)*CHAR_BIT isn't enough, you need a configuration check for
padding bits to be deducted. I don't see any helpful headers in C1X/C+
+0X.)
>> long maxsize1 = max( 0, 5098856789 ); // BOOM !!!
>
> Syntax error for pure C90/C++98. C99/C++0X compiles (the literal
> promotes to long long), but invokes undefined behavior from the
> downcast of long long to long. Presumably legal when targeting PDP-11
> (36-bit hardware char so int has at least 36 bits!).
You probably meant PDP-10, not PDP-11. The PDP-11 is very regular with
8 bits char, 16 bits int and 32 bits long. Its only real quirk is the
crooked endianness of long. That was the machine on which Unix and the C
language where invented.
For PDP-10 most implementations used 6 bits char (who needs lowercase
anyway?) or 9 bits char. Halfword int of 18 bits was also not unseen.
--
Greetings,
Jens Schmidt
The 2003 and 98 standards also say, in the very previous paragraph, that
"If it is decimal and has no suffix, it has the first of these types in
which its value can be represented: int, long int; if the value cannot
be represented as a long int, the behavior is undefined."
which makes me think that decimal integers with no suffix are meant to
be an exeption from the "ill-formed" rule.
But I see in C++ 0x that the UB paragraph is no longer there, looks like
they just fixed it. :)
Thank you,
Timothy Madden
The 2003 and 98 standards, also say, in the very previous paragraph,
that "If it is decimal and has no suffix, it has the first of these
types in which its value can be represented: int, long int; if the value
cannot be represented as a long int, the behavior is undefined." which I
tend to understand it is meant to be an exception from the general rule
that the program is ill-formed if the literal overflows.
Anyway that paragraph is no longer present in the C++ 0x draft, so I
they just fixed the problem.
Thank you,
Timothy Madden