ptrdiff_t maximum

B

Ben Bacarisse

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

They are mandatory for one C integer type: _Bool. They make perfect
sense.
 
P

Peter Nilsson

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.

What flaw? C99 has already fixed the lack of PTRDIFF_MAX and
requires all standard and extended integer types to have limit
macros.
 
S

Shao Miller

Keith said:
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.
I was quoting an ANSI C Standard draft (ANSI X3J11/88-090). If that
didn't make it into the ANSI C Standard X3.159-1989, then we can remove
the quotation marks and instead offer that it simply follows from the
'sizeof' operator that 'size_t' must be the integer type required to
hold the maximum size of an array.
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.
Do you perceive that the verity of the claim can be debated or were you
mostly curious where the quotation was from? :)
 
K

Keith Thompson

Shao Miller said:
I was quoting an ANSI C Standard draft (ANSI X3J11/88-090). If that
didn't make it into the ANSI C Standard X3.159-1989, then we can remove
the quotation marks and instead offer that it simply follows from the
'sizeof' operator that 'size_t' must be the integer type required to
hold the maximum size of an array.

Ok. The C90 standard has this in G.3.7.

G.3 says:

Each implementation shall document its behavior in each
of the areas listed in this subclause. The following are
implementation-defined:

G.3.7 Arrays and pointer:

The type of integer required to hold the maximum size of an
array -- that is, the type of the sizeof operator, size_t
(6.3.3.4, 7.1.1).

The corresponding section in C99 doesn't mention size_t. In fact,
the C99 section on implementation-defined behavior doesn't mention
size_t at all (which it probably should).
Do you perceive that the verity of the claim can be debated or were you
mostly curious where the quotation was from? :)

Both.

size_t isn't specifically related to arrays; it's the result of
sizeof, which can be applied to any object type. (It's also not 100%
clear that an array can't be bigger than size_t bytes.)
 
T

Tim Rentsch

The code below defines a macro TYPE_MAX(T) to find the maximum value
of a type T, producing a compile-time constant expression, and
dealing appropriately with possible padding bits. Disclaimers:

1. It relies on implementation-defined behavior for converting
out-of-range values in the case of signed types (mainly
that such conversions produce ordinary values within the
actual range of the type in question).

2. It doesn't work for a signed integer type of one bit (ie,
whose maximum value is 0).

3. It doesn't work for implementations whose largest unsigned
type has more than 16384 value bits.

4. It may produce results that are too low in C90 implementations
for types whose positive ranges exceed those of unsigned long.
Strictly speaking this would make the implementation be non-
conforming if one of those types were, eg, ptrdiff_t, but I
can't rule out the possibility that such implementations
exist. (A similar statement applies to C90 implementations
that define ULLONG_MAX badly; unfortunately it isn't possible
to protect against errant, non-conforming implementations.)

Despite the disclaimers it may be of practical value. I'd be
interested to hear of any failures to produce correct results.


/* File starts here */

#include <limits.h>

#define TYPE_MAX(T) ((T) TM_WT_( T, UNSIGNED_MAX_MAX ))


#if __STDC_VERSION__ > 199900L
#include <stdint.h>
#include <inttypes.h>

#if defined UINTMAX_MAX
#define UNSIGNED_MAX_MAX UINTMAX_MAX
#define UMAX_FORMAT PRIuMAX
typedef uintmax_t unsigned_max;

#elif defined ULLONG_MAX
#define UNSIGNED_MAX_MAX ULLONG_MAX
#define UMAX_FORMAT "llu"
typedef unsigned long long unsigned_max;

#else
#define UNSIGNED_MAX_MAX ULONG_MAX
#define UMAX_FORMAT "lu"
typedef unsigned long unsigned_max;

#endif

#elif defined ULLONG_MAX
#define UNSIGNED_MAX_MAX ULLONG_MAX
#define UMAX_FORMAT "llu"
typedef unsigned long long unsigned_max;

#else
#define UNSIGNED_MAX_MAX ULONG_MAX
#define UMAX_FORMAT "lu"
typedef unsigned long unsigned_max;

#endif


#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))

#if IMAX_BITS(UNSIGNED_MAX_MAX) > 16384
#error number of bits in UNSIGNED_MAX_MAX unreasonably high

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 8192
#define TM_WT_(T,v) TM_D_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 4096
#define TM_WT_(T,v) TM_C_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 2048
#define TM_WT_(T,v) TM_B_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 1024
#define TM_WT_(T,v) TM_A_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 512
#define TM_WT_(T,v) TM_9_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 256
#define TM_WT_(T,v) TM_8_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 128
#define TM_WT_(T,v) TM_7_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 64
#define TM_WT_(T,v) TM_6_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 32
#define TM_WT_(T,v) TM_5_(T,v)

#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 16
#define TM_WT_(T,v) TM_4_(T,v)

#else
#error number of bits in UNSIGNED_MAX_MAX impossibly low

#endif


#define TM_D_(T,v) ( TM_OK(T,v>>8181) ? TM_C_(T,v) : TM_C_(T,(v>>8192)) )
#define TM_C_(T,v) ( TM_OK(T,v>>4095) ? TM_B_(T,v) : TM_B_(T,(v>>4096)) )
#define TM_B_(T,v) ( TM_OK(T,v>>2047) ? TM_A_(T,v) : TM_A_(T,(v>>2048)) )
#define TM_A_(T,v) ( TM_OK(T,v>>1023) ? TM_9_(T,v) : TM_9_(T,(v>>1024)) )
#define TM_9_(T,v) ( TM_OK(T,v>> 511) ? TM_8_(T,v) : TM_8_(T,(v>> 512)) )
#define TM_8_(T,v) ( TM_OK(T,v>> 255) ? TM_7_(T,v) : TM_7_(T,(v>> 256)) )
#define TM_7_(T,v) ( TM_OK(T,v>> 127) ? TM_6_(T,v) : TM_6_(T,(v>> 128)) )
#define TM_6_(T,v) ( TM_OK(T,v>> 63) ? TM_5_(T,v) : TM_5_(T,(v>> 64)) )
#define TM_5_(T,v) ( TM_OK(T,v>> 31) ? TM_4_(T,v) : TM_4_(T,(v>> 32)) )
#define TM_4_(T,v) ( TM_OK(T,v>> 15) ? TM_3_(T,v) : TM_3_(T,(v>> 16)) )
#define TM_3_(T,v) ( TM_OK(T,v>> 7) ? TM_2_(T,v) : TM_2_(T,(v>> 8)) )
#define TM_2_(T,v) ( TM_OK(T,v>> 3) ? TM_1_(T,v) : TM_1_(T,(v>> 4)) )
#define TM_1_(T,v) ( TM_OK(T,v>> 1) ? TM_0_(T,v) : TM_0_(T,(v>> 2)) )
#define TM_0_(T,v) ( TM_OK(T,v ) ? v : v>> 1 )

#define TM_OK(T,v) ( (T)(v) > 0 && (T)(v) == (v) )


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

char test_array[ TYPE_MAX(char) ];

int
main(){
printf( " sizeof test_array is %25" UMAX_FORMAT "\n",
(unsigned_max) sizeof test_array
);
printf( "\n" );

#if __STDC_VERSION__ > 199900L
printf( "Maximum value of _Bool is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(_Bool)
);
printf( "\n" );
#endif

printf( "Maximum value of char is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(char)
);
printf( "Maximum value of signed char is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed char)
);
printf( "Maximum value of unsigned char is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned char)
);
printf( "\n" );

printf( "Maximum value of signed short is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed short)
);
printf( "Maximum value of unsigned short is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned short)
);
printf( "\n" );

printf( "Maximum value of signed int is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed int)
);
printf( "Maximum value of unsigned int is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned int)
);
printf( "\n" );

printf( "Maximum value of signed long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed long)
);
printf( "Maximum value of unsigned long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned long)
);
printf( "\n" );

printf( "Maximum value of ptrdiff_t is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(ptrdiff_t)
);
printf( "Maximum value of size_t is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(size_t)
);
printf( "\n" );

#if __STDC_VERSION__ > 199900L
printf( "Maximum value of signed long long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed long long)
);
printf( "Maximum value of unsigned long long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned long long)
);
printf( "\n" );
#endif

printf( " Value of UNSIGNED_MAX_MAX is %25" UMAX_FORMAT "\n",
(unsigned_max) UNSIGNED_MAX_MAX
);
printf( "\n" );

printf( " UMAX_FORMAT is %25s\n", UMAX_FORMAT );
printf( "\n" );

return 0;
}
 
S

Shao Miller

Keith said:
Shao Miller said:
Keith 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.
I was quoting an ANSI C Standard draft (ANSI X3J11/88-090). If that
didn't make it into the ANSI C Standard X3.159-1989, then we can remove
the quotation marks and instead offer that it simply follows from the
'sizeof' operator that 'size_t' must be the integer type required to
hold the maximum size of an array.

Ok. The C90 standard has this in G.3.7.

G.3 says:

Each implementation shall document its behavior in each
of the areas listed in this subclause. The following are
implementation-defined:

G.3.7 Arrays and pointer:

The type of integer required to hold the maximum size of an
array -- that is, the type of the sizeof operator, size_t
(6.3.3.4, 7.1.1).
Thanks for pointing out the correct section in the actual C90 Standard.
The corresponding section in C99 doesn't mention size_t. In fact,
the C99 section on implementation-defined behavior doesn't mention
size_t at all (which it probably should).
Oops! That might be a step backwards... Could it have been
intentional, I wonder?
So perhaps we follow along to 'sizeof'. Are arrays mentioned there?
Both.

size_t isn't specifically related to arrays; it's the result of
sizeof, which can be applied to any object type.
This might be perceived to be a little bit related to bounds-checking.
Here we have the notions of "array," "array type," and "array object."
We know[1] that we can define an array object with a declaration, but do
array objects (including multi-dimensional array objects) deserve
different treatment than "objects?"

If all objects have an object representation[2], does this include array
objects?
(It's also not 100%
clear that an array can't be bigger than size_t bytes.)
Heheh. I agree. Earlier I gave code which attempts to work with an
"array" (whatever that means) via pointer arithmetic beyond the limits
of 'size_t'.

I think it would be reasonable for one person to argue that a C array
object cannot have a size greater than the greatest value that can fit
within a 'size_t' and for another person to argue that 'size_t' and
array objects have no connection. :) Why? Because whether or not an
object is an array object seems to be relative to which part of the
Standard is used as qualifier.

void *vp;
vp = calloc(SIZE_MAX, 2);

Or:

size_t sz = sizeof (char[SIZE_MAX][2]);

Yikes. But it might be pleasant to work with such a large "array"
anyway. It's an example of asymmetry in the Standard, in my opinion.
We can attempt to construct an array with an arbitrarily large size and
we can attempt to increment a pointer to point to an arbitrarily high
element, but 'sizeof' yields 'size_t', which has a finite set of values
and pointer subtraction yields 'ptrdiff_t', which has a finite set of
values.

The C99 environmental limit for "bytes in an object" (hosted)[3] is
consistent with the minimum requirement for 'SIZE_MAX'[4].

Is the behaviour of these [clipped for brevity] code examples one or
more of: unspecified, implementation-defined, undefined? Or do we
additionally need "unknown"?

References from the "C99" C Standard draft with filename 'n1256.pdf':
[1] 6.5.2.1p4 "...Consider the array object defined by the declaration..."
[2] 6.2.6.1p4 "...any other object type..."
[3] 5.2.4.1p1 "...bytes in an object (in a hosted environment only)..."
[4] 7.18.3p2 "...limit of size_t..."
 
J

John Kelly

size_t sz = sizeof (char[SIZE_MAX][2]);

Yikes. But it might be pleasant to work with such a large "array"
anyway. It's an example of asymmetry in the Standard, in my opinion.
We can attempt to construct an array with an arbitrarily large size and
we can attempt to increment a pointer to point to an arbitrarily high
element, but 'sizeof' yields 'size_t', which has a finite set of values
and pointer subtraction yields 'ptrdiff_t', which has a finite set of
values.

The C99 environmental limit for "bytes in an object" (hosted)[3] is
consistent with the minimum requirement for 'SIZE_MAX'[4].

Is the behaviour of these [clipped for brevity] code examples one or
more of: unspecified, implementation-defined, undefined? Or do we
additionally need "unknown"?

How about FUBAR.
 
K

Keith Thompson

Shao Miller said:
Keith said:
Shao Miller said:
Keith Thompson wrote:
[...]
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.
I was quoting an ANSI C Standard draft (ANSI X3J11/88-090). If
that didn't make it into the ANSI C Standard X3.159-1989, then we
can remove the quotation marks and instead offer that it simply
follows from the 'sizeof' operator that 'size_t' must be the
integer type required to hold the maximum size of an array.

Ok. The C90 standard has this in G.3.7.

G.3 says:

Each implementation shall document its behavior in each
of the areas listed in this subclause. The following are
implementation-defined:

G.3.7 Arrays and pointer:

The type of integer required to hold the maximum size of an
array -- that is, the type of the sizeof operator, size_t
(6.3.3.4, 7.1.1).
Thanks for pointing out the correct section in the actual C90 Standard.
The corresponding section in C99 doesn't mention size_t. In fact,
the C99 section on implementation-defined behavior doesn't mention
size_t at all (which it probably should).
Oops! That might be a step backwards... Could it have been
intentional, I wonder?
So perhaps we follow along to 'sizeof'. Are arrays mentioned there?
No.

[...]
size_t isn't specifically related to arrays; it's the result of
sizeof, which can be applied to any object type.
This might be perceived to be a little bit related to
bounds-checking. Here we have the notions of "array," "array type,"
and "array object." We know[1] that we can define an array object with
a declaration, but do array objects (including multi-dimensional array
objects) deserve different treatment than "objects?"

IMHO, no, they don't.

Note that, for purposes of pointer arithmetic, any object can be treated
as a single-element array.
If all objects have an object representation[2], does this include
array objects?

Of course; why wouldn't it?
Heheh. I agree. Earlier I gave code which attempts to work with an
"array" (whatever that means) via pointer arithmetic beyond the limits
of 'size_t'.

I think it would be reasonable for one person to argue that a C array
object cannot have a size greater than the greatest value that can fit
within a 'size_t' and for another person to argue that 'size_t' and
array objects have no connection. :) Why? Because whether or not an
object is an array object seems to be relative to which part of the
Standard is used as qualifier.

I think you're overcomplicating this. Whether an object is an
array object simply depends on whether it's of array type. On the
other hand, as I mentioned, any object can be treated, for certain
well-defined purposes, as a single-element array object.
void *vp;
vp = calloc(SIZE_MAX, 2);

Or:

size_t sz = sizeof (char[SIZE_MAX][2]);

In the first case, any sane implementation will set vp to a null
pointer. In the second, an implementation can reject the type
char[SIZE_MAX][2] because it exceeds a capacity limit. If it
accepts it, since sizeof is an operator, I'd argue that the same
rules regarding overflow apply to it as to any other operator; if
the result would exceed SIZE_MAX, since size_t is an unsigned type,
the result is reduced modulo SIZE_MAX+1. I'm not particularly
happy with that interpretation.

Any sane implementation will simply make size_t big enough to
hold the size of any object it can support, and avoid the issue
altogether. The question (which is almost entirely theoretical
rather than practical) is whether the standard requires (or *should*
require) implementations to be sane.

malloc() already can't create objects bigger than SIZE_MAX bytes.
calloc() potentially can; the standard could be tweaked to require
it to fail if the mathematical product of tis two arguments exceeds
SIZE_MAX. An attempt to declare an object or type whose size
exceeds SIZE_MAX could be made a constraint violation. VLAs are
slightly tricky; probably all you could do is make the behavior of
huge VLAs undefined.
Yikes. But it might be pleasant to work with such a large "array"
anyway. It's an example of asymmetry in the Standard, in my
opinion. We can attempt to construct an array with an arbitrarily
large size and we can attempt to increment a pointer to point to an
arbitrarily high element, but 'sizeof' yields 'size_t', which has a
finite set of values and pointer subtraction yields 'ptrdiff_t', which
has a finite set of values.

The C99 environmental limit for "bytes in an object" (hosted)[3] is
consistent with the minimum requirement for 'SIZE_MAX'[4].

Is the behaviour of these [clipped for brevity] code examples one or
more of: unspecified, implementation-defined, undefined? Or do we
additionally need "unknown"?

References from the "C99" C Standard draft with filename 'n1256.pdf':
[1] 6.5.2.1p4 "...Consider the array object defined by the declaration..."
[2] 6.2.6.1p4 "...any other object type..."
[3] 5.2.4.1p1 "...bytes in an object (in a hosted environment only)..."
[4] 7.18.3p2 "...limit of size_t..."
 
S

Shao Miller

Keith said:
Shao Miller said:
Keith said:
Keith Thompson wrote:
[...]
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.
I was quoting an ANSI C Standard draft (ANSI X3J11/88-090). If
that didn't make it into the ANSI C Standard X3.159-1989, then we
can remove the quotation marks and instead offer that it simply
follows from the 'sizeof' operator that 'size_t' must be the
integer type required to hold the maximum size of an array.
Ok. The C90 standard has this in G.3.7.

G.3 says:

Each implementation shall document its behavior in each
of the areas listed in this subclause. The following are
implementation-defined:

G.3.7 Arrays and pointer:

The type of integer required to hold the maximum size of an
array -- that is, the type of the sizeof operator, size_t
(6.3.3.4, 7.1.1).
Thanks for pointing out the correct section in the actual C90 Standard.
The corresponding section in C99 doesn't mention size_t. In fact,
the C99 section on implementation-defined behavior doesn't mention
size_t at all (which it probably should).
Oops! That might be a step backwards... Could it have been
intentional, I wonder?
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.
So perhaps we follow along to 'sizeof'. Are arrays mentioned there?

No.
Are you serious? The semantics for the 'sizeof' operator doesn't
include any mention of arrays in the C90 Standard? It doesn't include
something like "...an operand that has array type..." and "...bytes in
the array."?
[...]
size_t isn't specifically related to arrays; it's the result of
sizeof, which can be applied to any object type.
This might be perceived to be a little bit related to
bounds-checking. Here we have the notions of "array," "array type,"
and "array object." We know[1] that we can define an array object with
a declaration, but do array objects (including multi-dimensional array
objects) deserve different treatment than "objects?"

IMHO, no, they don't. Agreed!

Note that, for purposes of pointer arithmetic, any object can be treated
as a single-element array.
Agreed (and thank goodness).
If all objects have an object representation[2], does this include
array objects?

Of course; why wouldn't it?
I cannot think of why array objects should not have an object
representation and am happy to claim that they do.
I think you're overcomplicating this. Whether an object is an
array object simply depends on whether it's of array type.
How do you make that type determination? Declared type? Effective
type? Use of 'calloc'? Access through unary '*'? If it's addressable?
Which of those choices leads to simple classification, or is there
another choice?
On the
other hand, as I mentioned, any object can be treated, for certain
well-defined purposes, as a single-element array object. Agreed.
void *vp;
vp = calloc(SIZE_MAX, 2);

Or:

size_t sz = sizeof (char[SIZE_MAX][2]);

In the first case, any sane implementation will set vp to a null
pointer.
Agreed. Then the "problem space" might be limited to dealing with
"unconventional" arrays, produced by other means (if that's allowed).
In the second, an implementation can reject the type
char[SIZE_MAX][2] because it exceeds a capacity limit. Right.

If it
accepts it, since sizeof is an operator, I'd argue that the same
rules regarding overflow apply to it as to any other operator; if
the result would exceed SIZE_MAX, since size_t is an unsigned type,
the result is reduced modulo SIZE_MAX+1.
That seems sensible.
I'm not particularly
happy with that interpretation.
That seems unfortunate.
Any sane implementation will simply make size_t big enough to
hold the size of any object it can support, and avoid the issue
altogether. The question (which is almost entirely theoretical
rather than practical)
If "practical" means not dealing with giant arrays from C, then fine.
is whether the standard requires (or *should*
require) implementations to be sane.
Oh this is a different question than I had in mind. It might be
beneficial to detail something in pointer arithmetic like "If an element
of an array is a distance greater than 'SIZE_MAX' bytes from the first
element, the behaviour is undefined." I don't think revoking an
implementation's license to define the undefined is particularly
beneficial, but I'd rather see it explicitly than "by omission."
malloc() already can't create objects bigger than SIZE_MAX bytes.
calloc() potentially can; the standard could be tweaked to require
it to fail if the mathematical product of tis two arguments exceeds
SIZE_MAX. An attempt to declare an object or type whose size
exceeds SIZE_MAX could be made a constraint violation. VLAs are
slightly tricky; probably all you could do is make the behavior of
huge VLAs undefined.
These could certainly help portability (after convincing implementors).
Then (again), the tricky area would be working with arrays not
produced within C.
 
S

Shao Miller

Uno said:
I think a form a saying "we should" that is philosophically well defined
is saying "this is part of our normative fabric," and take a vote on it.
That's what a good church council does.
I could be mistaken, but my impression is that the people responsible
for C Standards take votes and debate "ought" relative to a variety of
costs and potential benefits. Perhaps that's all Mr. K. Thompson meant
with that "should".
 
K

Keith Thompson

Shao Miller said:
Keith said:
Shao Miller said:
Keith Thompson wrote:
Keith Thompson wrote: [...]
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.
So perhaps we follow along to 'sizeof'. Are arrays mentioned there?

No.
Are you serious? The semantics for the 'sizeof' operator doesn't
include any mention of arrays in the C90 Standard? It doesn't include
something like "...an operand that has array type..." and "...bytes in
the array."?

C99's description of the "sizeof" operator mentions variable length
arrays, but that only affects whether the operand is evaluated.
I haven't checked C90.

Why should the description of "sizeof" mention array types specifically?
sizeof yields the size in bytes of its operand; why mention arrays in
that context? (The description of arrays probably says something about
their size.)

[...]
That seems sensible.

That seems unfortunate.

If I can have an object of size SIZE_MAX+42 bytes, having ``sizeof
obj'' yield 41 is utterly useless. Having ``sizeof obj'' trigger a
compile-time error would be far more sensible. But my interpretation
of the standard is that it should yield 41 (*if* such objects are
permitted, which they needn't be and IMHO shouldn't be).

[snip]
 
S

Shao Miller

Keith said:
Shao Miller said:
Keith said:
Keith Thompson wrote:
Keith Thompson wrote: [...]
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.
So perhaps we follow along to 'sizeof'. Are arrays mentioned there?
No.
Are you serious? The semantics for the 'sizeof' operator doesn't
include any mention of arrays in the C90 Standard? It doesn't include
something like "...an operand that has array type..." and "...bytes in
the array."?

C99's description of the "sizeof" operator mentions variable length
arrays, but that only affects whether the operand is evaluated.
I haven't checked C90.
Are you saying that 6.5.3.4p3 and 6.5.3.4p6 from 'n1256.pdf' didn't make
it into C99? If so... Yikes... They're still in the latest C1X draft
and seem to have endured at least since the ANSI draft I'd quoted before
from at least 21 years before now.
Why should the description of "sizeof" mention array types specifically?
sizeof yields the size in bytes of its operand; why mention arrays in
that context? (The description of arrays probably says something about
their size.)
Well, 'sizeof' is one of the cases where an array identifier doesn't
"decay" to a pointer; that might warrant mention.
[...]
That seems sensible.

That seems unfortunate.

If I can have an object of size SIZE_MAX+42 bytes, having ``sizeof
obj'' yield 41 is utterly useless. Having ``sizeof obj'' trigger a
compile-time error would be far more sensible. But my interpretation
of the standard is that it should yield 41 (*if* such objects are
permitted, which they needn't be and IMHO shouldn't be).
Sure! Why it bothers me is that we might try to work with a pointer
which points to something akin to (but larger than) a C array object,
but which is provided by something external to our program, such as
implementation or OS. Should C functions suddenly be rendered useless
on such odd, array-object-like entities? Would it be unfair to
repeatedly increment a pointer to access high elements but disallow
direct computation of pointers to high elements with an offset too large
for 'size_t' (or 'ptrdiff_t')?

It seems to me that 'SIZE_MAX' is pretty useful as the count of possible
pointer values (not object representations) given a contiguous range of
object storage, and 'ptrdiff_t' simply allows for a sign. But hey!
Suppose the hardware supports far fewer pointer values (for address
registers, perhaps) than it does values for the next-largest arithmetic
register... If 'size_t' is a typedef to a standard integer type, then
we really need 'SIZE_MAX' rather than relying on finding the maximum
value of the standard integer type. An arbitrary choice for an
alternative to a missing 'SIZE_MAX' in a C89 implementation might yield
unpleasant results when we increment a pointer one too many times.
Fortunately, the Standard evolves.

I don't fully understand why we have the optional 'intptr_t' and
'uintptr_t' types, _except_ that the sign of 'ptrdiff_t' allows a
possibly greater bit-width than 'size_t', but 'uintptr_t' seems to have
a greater bit-width than 'intptr_t'. Oh well.

I'd still be interested in anyone's response to:
 
U

Uno

Any sane implementation will simply make size_t big enough to
hold the size of any object it can support, and avoid the issue
altogether. The question (which is almost entirely theoretical
rather than practical) is whether the standard requires (or *should*
require) implementations to be sane.

malloc() already can't create objects bigger than SIZE_MAX bytes.
calloc() potentially can; the standard could be tweaked to require
it to fail if the mathematical product of tis two arguments exceeds
SIZE_MAX. An attempt to declare an object or type whose size
exceeds SIZE_MAX could be made a constraint violation. VLAs are
slightly tricky; probably all you could do is make the behavior of
huge VLAs undefined.

We hear misplaced "shoulds" all the time here in the states. It's the
same is-ought gap it's always been since David Hume.

Al Franken quips, "I'm should'ing all over myself."

"They should" is the constant drone from fixed noise. "The muslims
should not build here. "It should" doesn't work because objects lack
volition. "The sun should shine on everyone ... simultaneously." If
one is saying how an object is supposed to work, he can say "this
humdinger shall not bomb out."

I think a form a saying "we should" that is philosophically well defined
is saying "this is part of our normative fabric," and take a vote on it.
That's what a good church council does.
 
K

Keith Thompson

Shao Miller said:
Keith said:
Shao Miller said:
Keith Thompson wrote:
Keith Thompson wrote:
Keith Thompson wrote: [...]
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.
So perhaps we follow along to 'sizeof'. Are arrays mentioned there?
No.
Are you serious? The semantics for the 'sizeof' operator doesn't
include any mention of arrays in the C90 Standard? It doesn't include
something like "...an operand that has array type..." and "...bytes in
the array."?

C99's description of the "sizeof" operator mentions variable length
arrays, but that only affects whether the operand is evaluated.
I haven't checked C90.
Are you saying that 6.5.3.4p3 and 6.5.3.4p6 from 'n1256.pdf' didn't make
it into C99? If so... Yikes... They're still in the latest C1X draft
and seem to have endured at least since the ANSI draft I'd quoted before
from at least 21 years before now.

No, I'm saying that I managed to miss those paragraphs when I read it.
In other words, OOPS! My apologies.

(Incidentally, I was using n1256.pdf, which is a post-C99 draft
incorporating the original C99 standard plus the three Technical
Corrigenda. It wouldn't make sense for something in N1256 not to
"make it into C99".)

[59 lines deleted]

You might consider trimming quoted text that you're not commenting on.
 
J

James Waldby

On Fri, 27 Aug 2010 09:52:53 -0700, Tim Rentsch wrote:

....
#define TM_D_(T,v) ( TM_OK(T,v>>8181) ? TM_C_(T,v) : TM_C_(T,(v>>8192)) )
....

Presumably 8181 is a typo for 8191.
 
T

Tim Rentsch

James Waldby said:
On Fri, 27 Aug 2010 09:52:53 -0700, Tim Rentsch wrote:

...
...

Presumably 8181 is a typo for 8191.

Indeed so. Thank you for the correction.
 
S

Shao Miller

Keith said:
(Incidentally, I was using n1256.pdf, which is a post-C99 draft
incorporating the original C99 standard plus the three Technical
Corrigenda. It wouldn't make sense for something in N1256 not to
"make it into C99".)
Good point.
[59 lines deleted]

You might consider trimming quoted text that you're not commenting on.
Uh oh... I did have more responses in there... I hope my Thunderbird
isn't wrecking my posts...
 
K

Keith Thompson

christian.bau said:
There was a very long thread about this subject a year or two ago,
mostly about whether calloc could return a pointer to an array of more
than SIZE_MAX bytes, and what would be the consequences, and I think
the result was that

1. sizeof must return the size of an object.

sizeof yields a size_t, and it's tempting to conclude from that that
size_t must be able to represent the size of any object (or object
type), but there are objects to which sizeof cannot be applied.

How do you apply sizeof to an object created by calloc()?
The creation of the object doesn't impose a type on it, so you
can't use the ``sizeof ( type )'' form, and the object has no name,
so you can't use ``sizeof expr''. I suppose that, given
void *p = calloc(X, Y);
you could do
sizeof *(char(*)[X][Y])p
but that's not tied to the calloc().
2. If sizeof cannot return the size of an object because it is too
large, then behaviour is undefined.

I think you're right. Now that I re-read it, the sentence that requires
wraparound behavior for unsigned types (C99 6.2.5p9) says:

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.

Once could argue whether sizeof performs a "computation", but in
any case there are no unsigned *operands* involved. So I'd say
the behavior of ``sizeof whatever'', where ``whatever'' has a size
exceeding SIZE_MAX bytes, is undefined by omission.
The arithmetic operations with unsigned numbers are defined in such a
way that overflow is not possible, and the results are taken module
(SIZE_MAX + 1), but there are no such rules for sizeof, or for example
for strlen. Calling strlen for a string of more than SIZE_MAX
characters (if such a string could exist), would invoke undefined
behaviour as well.

Agreed.

On the other hand, consider this program:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(void)
{
char *p = calloc(SIZE_MAX, SIZE_MAX);
if (p == NULL) {
printf("calloc failed\n");
}
else {
strcpy(p, "Hello world -- it sure is roomy in here!");
puts(p);
}
return 0;
}

I would still argue that its behavior is not undefined, and I don't
know how to demonstrate from the standard that its output must be
"calloc failed". (I didn't even try to apply sizeof, so that's
not a source of UB.)

I think the *intent* is that size_t can represent the size in bytes of
any object, but as far as I can tell the standard never actually gets
around to saying so.
 
K

Keith Thompson

Shao Miller said:
Keith said:
(Incidentally, I was using n1256.pdf, which is a post-C99 draft
incorporating the original C99 standard plus the three Technical
Corrigenda. It wouldn't make sense for something in N1256 not to
"make it into C99".)
Good point.
[59 lines deleted]

You might consider trimming quoted text that you're not commenting on.
Uh oh... I did have more responses in there... I hope my Thunderbird
isn't wrecking my posts...

My apologies again. You did have more original text in there.
Obviously there's too much blood in my caffeinestream.
 

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

Forum statistics

Threads
474,083
Messages
2,570,591
Members
47,212
Latest member
RobynWiley

Latest Threads

Top