Reputation:
#include <cstdint>
#include <iostream>
int main() {
uint32_t i = -64;
int32_t j = i;
std::cout << j;
return 0;
}
Most compilers I've tried will create programs that output -64
, but is this defined behaviour?
uint32_t i = -64;
defined behaviour?int32_t j = i;
, when i
equals 4294967232
, defined behaviour?Upvotes: 17
Views: 4823
Reputation: 31
It's well defined in C++20, according to N2218 Signed Integers are Two’s Complement and P1236R1.
Prior to C++20, this behaviour is the defacto standard. Can assume that it's true in the C++ world from the begining. C++20 just standardize it.
Upvotes: 1
Reputation: 81153
The Standard requires that implementations document, somehow, how they will determine what value to use when an integer is converted to a signed type which is too small to accommodate it. It does not specify the form such documentation will take. A conforming implementation's documentation could specify in readable print that values will be truncated and two's-complement sign extended, and then in impossibly small print specify "...except when a program is compiled on the fifth Tuesday of a month, in which case out-of-range conversions will yield the value 24601". Such documentation would, of course, be less than helpful, but the Standard does not concern itself with "quality of implementation" issues.
In practice, implementations that define the behavior in any fashion other than 100% consistent truncation and two's-complement sign extension are extremely rare; I would not be particularly surprised if in fact 100% of conforming C99 and C11 implementations that are intended for production code default to working in that fashion. Unfortunately, neither <limits.h>
nor any other standard header defines any means via which implementations can indicate that they follow the essentially-universal convention.
To be sure, it's unlikely that code which expects the common behavior will be tripped up by the behavior of any conforming compiler. It's plausible, however, that compilers might offer a non-conforming mode, since that could make certain kinds of code more efficient. For example, given:
int32_t x,i;
int16_t *p;
...
x = ++p[i];
If int
is larger than 16 bits, behavior would be defined in case p[i]
was 32767 before the code executed. The increment would yield -32768, the value would be converted to int16_t
in Implementation-Defined fashion (which is guaranteed to yield -32768 unless an implementation documents something else), and that value would then be stored to both x
and p[i]
.
On processors like the ARM which always do arithmetic using 32 bits, truncating the value stored to p[i]
would cost nothing, but truncating the value written to x
would require an instruction (or, for some older ARM models, two instructions). Allowing x
to receive +32768 in that case would improve efficiency on such processors. Such an option would not affect the behavior of most programs, but it would be helpful if the Standard defined a means via which code which relied upon behavior could say, e.g.
#ifdef __STDC_UNUSUAL_INT_TRUNCATION
#error This code relies upon truncating integer type conversions
#endif
so that those programs that would be affected could guard against accidental compilation in such modes. As yet the Standard doesn't define any such test macro.
Upvotes: 1
Reputation: 122383
For unsigned integer out-of-range conversion, the result is defined; for signed integers, it's implementation-defined.
C++11(ISO/IEC 14882:2011) §4.7 Integral conversions [conv.integral/2]
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). —end note ]
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.
This text remains the same for C++14.
Upvotes: 9