K
Keith Thompson
Thomas Scrace said:Well it turned out that you are correct. I have discussed this in previous
posts, but, briefly, I had a bug that caused the function to give me the
result I was looking for, but using a method I was not expecting.
The reason was that I was initiating a loop by assinging -1 to an unsigned type.
This meant that the variable immediately had the max value, and the loop exited
without looping through all the possible values of the unsigned type (which is
what I thought it was doing).
From my perspective this meant that the program was looping through a large
number of values extremely quickly in comparison with the signed version of the
function, which was extremely slow (it actually *was* looping through all the
values).
I have posted the full version of the program I ended up with in a previous
message if you are interested.
Thanks for the information - it was very interesting.
This program makes some non-portable assumptions, but it should work as
expected on any system you're likely to encounter.
#include <stdio.h>
int main(void)
{
const unsigned char uchar_max = -1;
const signed char schar_max = uchar_max / 2u;
const unsigned short ushrt_max = -1;
const signed short shrt_max = ushrt_max / 2u;
const unsigned int uint_max = -1;
const signed int int_max = uint_max / 2u;
const unsigned long ulong_max = -1;
const signed long long_max = ulong_max / 2ul;
const unsigned long long ullong_max = -1;
const signed long long llong_max = ullong_max / 2ull;
printf("schar_max = %20d\n", schar_max);
printf("uchar_max = %20u\n", (unsigned)uchar_max);
printf("shrt_max = %20d\n", shrt_max);
printf("ushrt_max = %20u\n", (unsigned)ushrt_max);
printf("int_max = %20d\n", int_max);
printf("uint_max = %20u\n", uint_max);
printf("long_max = %20ld\n", long_max);
printf("ulong_max = %20lu\n", ulong_max);
printf("llong_max = %20lld\n", llong_max);
printf("ullong_max = %20llu\n", ullong_max);
return 0;
}
It's reliable for the unsigned types; -1 converted to any unsigned type
always yields the maximum value of that type.
For the signed types, it simply assumes that the maximum value is half
the maximum value of the corresponding signed type (with truncating
division); for example, if USHRT_MAX is 65535, it assumes SHRT_MAX is
32767. This is likely to be true even on systems that don't use
2's-complement. It will break down only if corresponding signed and
unsigned types have different numbers of padding bits. (Most or all
modern systems have no padding bits.)
Computing the minimum value for signed types is less straightforward.
It's likely to be either -FOO_MAX-1 (2's-complement) or -FOO_MAX
(1s'-complement or sign-and-magnitude), and you can (99%-reliably)
determine which representation is used by type-punning (e.g., set
the signed member of a union to -1 and see what value the unsigned
value takes on). This will fail if a system uses 2's-complement
but chooses to make the minimum representable value a trap
representation.
Of course it's easier just to use <limits.h>, but perhaps this kind of
technique could be useful for someone *implementing* <limits.h>.