Is this a safe way to determine the maximum value of an integer without using the limits
library?
int max_int = (unsigned int) -1 >> 1;
Is this a safe way to determine the maximum value of an integer without using the limits
library?
int max_int = (unsigned int) -1 >> 1;
I believe that the code you proposed:
int max_int = (unsigned int) -1 >> 1;
is not a safe way to determine the maximum value of a signed integer type (according to the standard), but it should definitely work on most architectures. I'll try to carefully motivate the statement below.
The first thing to notice is that:
6.2.5 Types
...
For each of the signed integer types, there is a corresponding (but different) unsigned integer type (designated with the keyword unsigned) that uses the same amount of storage (including sign information) and has the same alignment requirements. ...
The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same. A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
These lines of the standard ensure that (unsigned int) -1
is converted to UINT_MAX
. Then the following:
6.5.7 Bitwise shift operators
...
- The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2^E2.
ensures that the value of the number is divided by 2. Now it comes the tricky point. According to the following:
6.2.6.2 Integer types
- For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N value bits, each bit shall represent a different power of 2 between 1 and 2N-1, so that objects of that type shall be capable of representing values from 0 to 2N - 1 using a pure binary representation; this shall be known as the value representation. The values of any padding bits are unspecified.
- For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; there shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M <= N).
signed integer types are composed of:
while unsigned integer types are composed of:
Due to the fact that signed and unsigned integers of corresponding types must have the same storage, I argue that M+X+1 == N+Y
.
Your assumption, when shifting of only one bit is that M = N - 1
or, otherwise stated, that the number of padding bits in an int
is the same as that of an unsigned int
.
Now, given the conversion rule:
6.3.1.3 Signed and unsigned integers
- When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
- Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
if your assumption is correct on the architecture you are working on, you will hit the first bullet, otherwise you'll hit the third and the behavior will be implementation defined.
The latter option won't be "safe", as you can't ensure a unique behavior for your program based on the C standard only, and you can't rely on an implementation to have some feature you may need to handle that case properly.