On 5/30/20 2:48 AM, James Kuyper wrote:
On 5/29/20 9:55 PM, Spiros Bousbouras wrote:
Assume an implementation with 2 extended integer types as follows :
I suspect that you don't mean the following type names to be interpreted literally, but it would have been better for you to choose identifiers
for those types which are reserved to the implementation, such as
__int24_t and __uint40_t.
- INT1 is signed , has 23 value bits and no corresponding unsigned type.
"The standard and extended signed integer types are collectively called signed integer types." (6.2.5p4).
"For each of the signed integer types, there is a corresponding (but different) unsigned integer type ..." (6.2.5p6).
There's an additional requirement which wasn't relevant to what I said
last night, but is relevant to my corrections below: "... that uses the
same amount of storage. ...". I get the impression that you chose 23
bits to fit in 3 8-bit bytes, and 40 bits to fit in 5 8-bit bytes. If
so, then the corresponding unsigned type can have at most 24 bits.
- UINT1 is unsigned , has 40 value bits and no corresponding signed type.
That, however, is permitted, since 6.2.5p6 is asymmetrical.
- Both have rank greater than int .
- The rank of UINT1 is smaller than the rank of INT1 .
The last stipulation is perverse but I don't see anything in "6.3.1.1
Boolean, characters, and integers" which forbids it.
I believe you are correct about that, and I agree that it's a problem -
but not because of what you wrote below:
That didn't seem right to me. I was sure there was a relevant clause prohibiting it. However, I couldn't find it, so I assumed I might have
been remembering incorrectly. The problem was that I was assuming it
should be somewhere under 6.3.1.1, whereas it's actually in 6.2.5p8:
"For any two integer types with the same signedness and different
integer conversion rank (see 6.3.1.1), the range of values of the type
with smaller integer conversion rank is a subrange of the values of the
other type."
I must have been up too late last night - a search I remember performing
should have turned up that clause. My wife and I are luckily both able
to continue telecommuting full-time during this pandemic, but the twins' preschool is closed. Finding enough time to get everything done has been difficult.
Since there is required to be an unsigned integer type corresponding to
INT1, then if that type has only 24 bits, it must have a rank lower than
that of UINT1.
"The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any." (6.3.1.1p1).
Therefore, the rank of INT1 must be the same as the rank of its
corresponding unsigned type, and therefore must be less than the rank of
UINT1.
There is a way around this - you could have sizeof(INT1) = 6, with 24
padding bits - quite perverse, but permitted by the standard. The
corresponding unsigned type could then have 48 value bits, in which case
their shared rank would have to be greater than UINT1.
With the above , if you have an addition where one operand is of type INT1 >> and the other of type UINT1 then none of the possibilities (rules) in
"6.3.1.8 Usual arithmetic conversions" after the part "Otherwise, the integer
promotions are performed on both operands. Then the following rules are
applied to the promoted operands:" is applicable.
Since there is required to be a corresponding unsigned integer type, the
last rule would apply:
"Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type."
That rule specifies a conversion that would loose information from the
signed value, which is what I consider to be bad about the fact that
such an implementation is allowed.
You can still get into this situation with my 48 bit scenario, but it's
no longer problematic, since in that case the corresponding unsigned
type is big enough that no information will be lost.
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)