R
Rade
Following a discussion on another thread here... I have tried to understand
what is actually standardized in C++ regarding the representing of integers
(signed and unsigned) and their conversions. The reference should be 3.9.1
(Fundamental types), and 4.7 (Integral conversions).
It seems to me that the Standard doesn't specify:
1) The "value representation" of any of these types, except that (3.9.1/3)
"... The range of nonnegative values of a signed integer type is a subrange
of the corresponding unsigned integer type, and the value representation of
each corresponding signed/unsigned type shall be the same."
2) The conversion from an unsigned type to a signed type when the signed
type can't represent the value.
I have three questions:
1) The cited sentence from 3.9.1/3 is not clear to me. How, for example, the
value representation for int and unsigned int can be the same as they have
different sets of values? Shouldn't this sentence be restricted just to
representations of these values that are common to both types (i.e.
nonnegative ints) ?
2) Am I missing something, or there is really no word in the Standard about
the "value representations" of unsigned types? 3.9.1/4 obviously describes
just the arithmetic laws for unsigned types, but has nothing with their
"value representations". Imagine we use 2 bits to represent unsigned int,
with the set of values 0-3 and set of bit patterns 00, 01, 10, 11. One would
expect that the following condition is always true:
n == (n & 1) + (n & (1 << 1));
(deliberately mixing arithmetic and bitwise operators). However, what if the
value 1 is represented as 11 and 2 is represented as 00 (does anything in
the Standard preclude such a representation?)? Then 1 << 1 is 2 (i.e. 00),
the first operand of + is equal to n, the second is equal to 00, i.e. 2, and
the result on the right side is actually n+2 (mod 4), not n.
(see also 5.8: operators << and >> are actually arithmetic operators, not
bitwise operators, as they are defined on values, not on representations.
This means that even replacing + with | wouldn't help in some cases).
If this is possible (at least on some weird but conforming implementation of
the Standard), then one could hardly find a portable nontrivial C++ program
in the world.
3) I haven't seen any additional rules for conversions from unsigned to
signed types in case the signed type has the same (or greater - can it
happen with a conforming implementation???) number of bits as the unsigned
type, but still can't contain the value from the unsigned type. For
example - conversions from unsigned int to int when the unsigned int value
is greater than INT_MAX... (the opposite conversion is well-defined by
4.7/2). If this is implementation-defined, that would mean, for example:
// -1 is int and is converted to 2^n-1 by 4.7/2
unsigned minusOneUnsigned = -1;
// implementation-defined, may be -0 on 1's complement machine
int minusOneInt = minusOneUnsigned;
// modulo 2^n conversion again, but of which value ?
unsigned minusOneUnsignedAgain = minusOneInt;
- we can't tell what the value of minusOneUnsignedAgain will be, after a
double conversion.
My question is: does C++ standard specify anything in this case? I can
understand that our minusOneUnsignedAgain can be 0, after all, instead of
2^n-1, but this seems counterintuitive to me.
Regards,
Rade
what is actually standardized in C++ regarding the representing of integers
(signed and unsigned) and their conversions. The reference should be 3.9.1
(Fundamental types), and 4.7 (Integral conversions).
It seems to me that the Standard doesn't specify:
1) The "value representation" of any of these types, except that (3.9.1/3)
"... The range of nonnegative values of a signed integer type is a subrange
of the corresponding unsigned integer type, and the value representation of
each corresponding signed/unsigned type shall be the same."
2) The conversion from an unsigned type to a signed type when the signed
type can't represent the value.
I have three questions:
1) The cited sentence from 3.9.1/3 is not clear to me. How, for example, the
value representation for int and unsigned int can be the same as they have
different sets of values? Shouldn't this sentence be restricted just to
representations of these values that are common to both types (i.e.
nonnegative ints) ?
2) Am I missing something, or there is really no word in the Standard about
the "value representations" of unsigned types? 3.9.1/4 obviously describes
just the arithmetic laws for unsigned types, but has nothing with their
"value representations". Imagine we use 2 bits to represent unsigned int,
with the set of values 0-3 and set of bit patterns 00, 01, 10, 11. One would
expect that the following condition is always true:
n == (n & 1) + (n & (1 << 1));
(deliberately mixing arithmetic and bitwise operators). However, what if the
value 1 is represented as 11 and 2 is represented as 00 (does anything in
the Standard preclude such a representation?)? Then 1 << 1 is 2 (i.e. 00),
the first operand of + is equal to n, the second is equal to 00, i.e. 2, and
the result on the right side is actually n+2 (mod 4), not n.
(see also 5.8: operators << and >> are actually arithmetic operators, not
bitwise operators, as they are defined on values, not on representations.
This means that even replacing + with | wouldn't help in some cases).
If this is possible (at least on some weird but conforming implementation of
the Standard), then one could hardly find a portable nontrivial C++ program
in the world.
3) I haven't seen any additional rules for conversions from unsigned to
signed types in case the signed type has the same (or greater - can it
happen with a conforming implementation???) number of bits as the unsigned
type, but still can't contain the value from the unsigned type. For
example - conversions from unsigned int to int when the unsigned int value
is greater than INT_MAX... (the opposite conversion is well-defined by
4.7/2). If this is implementation-defined, that would mean, for example:
// -1 is int and is converted to 2^n-1 by 4.7/2
unsigned minusOneUnsigned = -1;
// implementation-defined, may be -0 on 1's complement machine
int minusOneInt = minusOneUnsigned;
// modulo 2^n conversion again, but of which value ?
unsigned minusOneUnsignedAgain = minusOneInt;
- we can't tell what the value of minusOneUnsignedAgain will be, after a
double conversion.
My question is: does C++ standard specify anything in this case? I can
understand that our minusOneUnsignedAgain can be 0, after all, instead of
2^n-1, but this seems counterintuitive to me.
Regards,
Rade