ptrdiff_t maximum

B

Ben Bacarisse

John Kelly said:
Here's another try at the elusive universal solution for the maximum
value of any signed type.

# define MAX_SIGNED_BITS(type) (sizeof (type) * CHAR_BIT - 1)

# define MAX_SIGNED(type, name) \
\
type \
name ## _max_ (void)\
{ \
type last; \
int tn, bits = MAX_SIGNED_BITS(type); \
for (last = 1, tn = 1; tn < bits; tn++) { \
last = last * 2 + 1; \
} \
return last; \
}

Why the loop? The result is statically determined from the value of
MAX_SIGNED_BITS(type). If the type has padding bits, this method does
not work. If you are happy with a solution that assumes there are no
padding bits, then a version has already been posted that produces
a compile-time constant. No need for a function nor a loop.
MAX_SIGNED (short, short);
MAX_SIGNED (ptrdiff_t, ptrdiff_t);
MAX_SIGNED (long long, long_long);

int
main (void)
{
short const short_max = short_max_ ();
ptrdiff_t const ptrdiff_t_max = ptrdiff_t_max_ ();
long long const long_long_max = long_long_max_ ();

printf ("short_max = %d\n", short_max);
printf ("ptrdiff_t_max = %d\n", ptrdiff_t_max);

This is undefined. In C99 there is the t size modifier and in C90
ptrdiff_t can't be wider than long so casting to long and using %ld is
the standard way to print a ptrdiff_t.
 
J

John Kelly

Why the loop? The result is statically determined from the value of
MAX_SIGNED_BITS(type). If the type has padding bits, this method does
not work.

I can't find much info on the padding bits you mention. Can you
elaborate?

If you are happy with a solution that assumes there are no
padding bits, then a version has already been posted that produces
a compile-time constant.

Ian's solution did not work for me, when I tried it with long long.
Does it work for you?

No need for a function nor a loop.


This is undefined. In C99 there is the t size modifier and in C90
ptrdiff_t can't be wider than long

Printing formats aside, how does the t size modifier help me derive the
maximum positive value for a signed type? And In C90, what guarantees
that ptrdiff_t is not shorter than long?

I'm looking for a solution that works with any signed type, not just
ptrdiff_t, for C90 or C99.
 
B

Ben Bacarisse

John Kelly said:
I can't find much info on the padding bits you mention. Can you
elaborate?

6.2.6.2. Basically they are bits that have to be included in the size
of the object but which don't contribute to the value.
Ian's solution did not work for me, when I tried it with long long.
Does it work for you?

I don't know. If you re-post it I'll check. I was talking about the
expression I posted:

#include <stddef.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>

#define MAX_OF(t) \
(((t)1 << sizeof(t) * CHAR_BIT - 2) - 1 + \
((t)1 << sizeof(t) * CHAR_BIT - 2))

#define test(t, max) \
printf("%20s =%20jd %12s =%20jd\n", \
"MAX_OF("#t")", (intmax_t)MAX_OF(t), \
#max, (intmax_t)(max))

int main(void)
{
test(signed char, SCHAR_MAX);
test(short, SHRT_MAX);
test(int, INT_MAX);
test(long, LONG_MAX);
test(long long, LLONG_MAX);
test(intmax_t, INTMAX_MAX);
test(ptrdiff_t, PTRDIFF_MAX);
test(intptr_t, INTPTR_MAX);
return 0;
}

Which, for me, produces:

MAX_OF(signed char) = 127 SCHAR_MAX = 127
MAX_OF(short) = 32767 SHRT_MAX = 32767
MAX_OF(int) = 2147483647 INT_MAX = 2147483647
MAX_OF(long) = 9223372036854775807 LONG_MAX = 9223372036854775807
MAX_OF(long long) = 9223372036854775807 LLONG_MAX = 9223372036854775807
MAX_OF(intmax_t) = 9223372036854775807 INTMAX_MAX = 9223372036854775807
MAX_OF(ptrdiff_t) = 9223372036854775807 PTRDIFF_MAX = 9223372036854775807
MAX_OF(intptr_t) = 9223372036854775807 INTPTR_MAX = 9223372036854775807

Obviously, you need to change this if you don't have (close to) a C99
compiler since some of the types and or _MAX macros will be missing.

Printing formats aside, how does the t size modifier help me derive the
maximum positive value for a signed type?

Not everything I say is directed toward your narrow goals. I mention it
so that you can avoid undefined behaviour.
And In C90, what guarantees
that ptrdiff_t is not shorter than long?

Nothing, because there is no such guarantee. What made you think there
might be?
I'm looking for a solution that works with any signed type, not just
ptrdiff_t, for C90 or C99.

Ignoring the possibility of padding bits or not?
 
J

John Kelly

I don't know. If you re-post it I'll check. I was talking about the
expression I posted:

OK. I saw that before, but it got lost in the shuffle. I'll take a
closer look this time.

Thanks.
 
J

John Kelly

6.2.6.2. Basically they are bits that have to be included in the size
of the object but which don't contribute to the value.

I can see how that might be true for a pointer, but it makes no sense to
implement an integer type that way.

Of course I am trying to derive the range of ptrdiff_t, so that could be
a problem, lacking a preassigned constant like PTRDIFF_T.

So PTRDIFF_T, when present, is specific to the address bits on any given
platform. That's fine for C99, where you have the constant, but muddies
the C90 portability waters.
 
S

Seebs

I can see how that might be true for a pointer, but it makes no sense to
implement an integer type that way.

Nonetheless, it happens in the real world. Things don't have to make sense
to you in order to happen.

-s
 
J

John Kelly

Ignoring the possibility of padding bits or not?

If there is no way to determine the number of paddling bits for a given
type, and thus its range, that is a flaw in the standard.
 
S

Seebs

If there is no way to determine the number of paddling bits for a given
type, and thus its range, that is a flaw in the standard.

Most people avoid eating stuff that makes them sick. A special few, though,
have the vision to declare it a flaw in the world that there exist substances
they can't just shove in their mouth without thinking about it.

-s
 
J

John Kelly

(((t)1 << sizeof(t) * CHAR_BIT - 2) - 1 + \
((t)1 << sizeof(t) * CHAR_BIT - 2))

After taking a closer look at this, I see what it's doing. Good
solution. My compiler warned about parentheses on the shift, so I added
some to make it quiet.

Ignoring the possibility of padding bits or not?

Well, since the standard does not provide any way of determining the
number of padding bits for a given type, and thus its true range, what
else can I do, but ignore them?
 
K

Keith Thompson

Ian Collins said:
On 08/27/10 02:46 AM, John Kelly wrote: [...]
I can't get it to work for long long. Does it work for you?

Change the 1UL to 1ULL. But remember both "1ULL" and long long are from
C99.

Also remember that many compilers that don't fully support C99 still
implement long long. Which means that something like this:

#if __STDC_VERSION__ >= 199901L
typedef long long big_int;
#else
typedef long big_int;
#endif

could easily define big_int as long even on a system that supports long
long. Checking whether LLONG_MAX is defined in <limits.h> is probably
your best bet in this particular case, but there's no general way to
determine whether a given C99-specific feature is implemented in a
compiler that doesn't claim full C99 support.
 
S

Shao Miller

John said:
After taking a closer look at this, I see what it's doing. Good
solution. My compiler warned about parentheses on the shift, so I added
some to make it quiet.



Well, since the standard does not provide any way of determining the
number of padding bits for a given type, and thus its true range, what
else can I do, but ignore them?
If '__STDC_VERSION__' is '199901L', you can use 'SIZE_MAX' or
'PTRDIFF_MAX', if you like. Otherwise, you can use a window size that
is guaranteed to fit in a 'size_t' and call 'memmove' multiple times, up
to your arbitrary maximum in your attempt for infinite loop prevention.

In C89, I believe we have in A.6.3.6 that 'size_t' is "The type of
integer required to hold the maximum size of an array".

Since pointer arithmetic is only defined for array objects, it would
seem that 'size_t' is a fair candidate for your infinite loop prevention.

Since 'memmove' takes a 'size_t', it would seem that 'size_t' is a fair
candidate for your infinite loop prevention.

Since you can increment counts, you can avoid pointer subtraction and
'ptrdiff_t'.

Since C89 offers 32,767 bytes in an object (in a hosted environment), so
perhaps that's a safe maximum to plug into 'size_t'. Otherwise,
unsigned operands in C89 don't overflow, so you can establish your
maximum at run-time with a loop which checks for wrap-around to zero...
You could memoize the result for a one-time computation cost
(heheheheheh).

Or you could use '((size_t)((signed char)-1))', perhaps.
 
P

Peter Nilsson

John Kelly said:
Well, since the standard does not provide any way of
determining the number of padding bits for a given type,

Determining the number of padding bits in an unsigned
type is simple in both C90 and C99. Since there's a way to
determine the maximum type of any signed type in C90, there
is therefore a way of determining the number of padding bits.
 
K

Keith Thompson

Shao Miller said:
In C89, I believe we have in A.6.3.6 that 'size_t' is "The type of
integer required to hold the maximum size of an array".

What document are you quoting? In the C90 standard, Annex A is
the bibliography; there is no A.6.3.6. C90 6.3.6 covers additive
operators; it doesn't mention size_t. I don't see the quoted
sentence in either edition of K&R, though I haven't searched
thoroughly; neither has an A.6.3.6.

C90 7.1.6 merely says that size_t is "the unsigned integral type
of the result of the sizeof operator", with no mention of arrays.
C99 7.17p2 has the same wording.

[...]
 
J

John Kelly

Determining the number of padding bits in an unsigned
type is simple in both C90 and C99. Since there's a way to
determine the maximum type of any signed type in C90, there
is therefore a way of determining the number of padding bits.

Are they family secrets?
 
B

Ben Bacarisse

John Kelly said:
If there is no way to determine the number of paddling bits for a given
type, and thus its range, that is a flaw in the standard.

In C99 you can work backwards. The XXX_MAX macros let you determine the
number of padding bits in the XXX type.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top