Origin of size_t? Curious.

C

Confused User

I am curious what the origins of size_t are. I see that it is usually
typedef'd to be the native integer size of a particular machine. I also see
that routines like strncpy(char *t, const char *s, size_t n).

So, is size_t the native size of the machine or used to describe the actual
size of something (like the len of a string copy).

If it is named because it designates the size of something, then could I
still have more than 65535 bytes of something. If so why is that called
size_t.

I understand that it is just an int, but I don't understand the name. I can
have a size that is larger than an int. Perhaps I could store the size of
something in long? Wow?!?!?!

What the heck are the origins for the name?

Elvis
 
M

Morris Dovey

Confused User affirmed:

| I am curious what the origins of size_t are. I see that it is
| usually typedef'd to be the native integer size of a particular
| machine. I also see that routines like strncpy(char *t, const char
| *s, size_t n).
|
| So, is size_t the native size of the machine or used to describe
| the actual size of something (like the len of a string copy).
|
| If it is named because it designates the size of something, then
| could I still have more than 65535 bytes of something. If so why is
| that called size_t.
|
| I understand that it is just an int, but I don't understand the
| name. I can have a size that is larger than an int. Perhaps I could
| store the size of something in long? Wow?!?!?!
|
| What the heck are the origins for the name?

A size_t is large enough to represent the largest number of
<something> possible to the implementation. It need not be an int and,
in fact, it'd probably make more sense for it to be a long int. An
unsigned long would seem even better; but would prevent returning
(size_t) -1 for an error value.

Why size_t at all? So that we can recompile libraries and applications
for new systems (with different size size_t values) by modifying only
the size_t definition.
 
C

Clark S. Cox III

A size_t is large enough to represent the largest number of
<something> possible to the implementation. It need not be an int and,
in fact, it'd probably make more sense for it to be a long int. An
unsigned long would seem even better; but would prevent returning
(size_t) -1 for an error value.

You are mistaken, size_t is never signed, so it cannot possibly be int
or long int.
 
G

Gordon Burditt

I am curious what the origins of size_t are. I see that it is usually
typedef'd to be the native integer size of a particular machine. I also see
that routines like strncpy(char *t, const char *s, size_t n).

So, is size_t the native size of the machine or used to describe the actual
size of something (like the len of a string copy).

If it is named because it designates the size of something, then could I
still have more than 65535 bytes of something.

Really? How? malloc() takes a size_t as an argument, so you can't
malloc() anything bigger. And if you can't take sizeof(struct foo),
it isn't necessary for it to allow your declaration of struct foo
that exceeds the limits of a size_t. The same applies to large arrays.
I understand that it is just an int, but I don't understand the name. I can

It's not an int. Unsigned int, maybe. Unsigned long is more likely.
have a size that is larger than an int. Perhaps I could store the size of
something in long? Wow?!?!?!

Gordon L. Burditt
 
M

Morris Dovey

Clark S. Cox III affirmed:

| On 2005-06-22 21:29:29 -0400, "Morris Dovey" <[email protected]>
| said:
|| A size_t is large enough to represent the largest number of
|| <something> possible to the implementation. It need not be an int
|| and, in fact, it'd probably make more sense for it to be a long
|| int. An unsigned long would seem even better; but would prevent
|| returning (size_t) -1 for an error value.
|
| You are mistaken, size_t is never signed, so it cannot possibly be
| int or long int.

Clark...

You're absolutely right. In 7.17.2 it's spec'd as "the unsigned
integer type of the result of the *sizeof* operator".

I should've looked before posting. Thanks!
 
R

Robert Gamble

Morris said:
Confused User affirmed:

| I am curious what the origins of size_t are. I see that it is
| usually typedef'd to be the native integer size of a particular
| machine. I also see that routines like strncpy(char *t, const char
| *s, size_t n).
|
| So, is size_t the native size of the machine or used to describe
| the actual size of something (like the len of a string copy).
|
| If it is named because it designates the size of something, then
| could I still have more than 65535 bytes of something. If so why is
| that called size_t.
|
| I understand that it is just an int, but I don't understand the
| name. I can have a size that is larger than an int. Perhaps I could
| store the size of something in long? Wow?!?!?!
|
| What the heck are the origins for the name?

A size_t is large enough to represent the largest number of
<something> possible to the implementation. It need not be an int and,
in fact, it'd probably make more sense for it to be a long int. An
unsigned long would seem even better; but would prevent returning
(size_t) -1 for an error value.

size_t must be an unsigned integer type and thus can never represent a
negative value. (size_t) -1 would be equivalent to SIZE_MAX.

Robert Gamble
 
P

P.J. Plauger

You're absolutely right. In 7.17.2 it's spec'd as "the unsigned
integer type of the result of the *sizeof* operator".

Yep. Its origins lie in the old <std.h> header we developed at
Whitesmiths, Ltd. in the late 1970s. We used the typedef BYTES
as the type of sizeof, to be sure we could count all the bytes
in the largest declarable (or allocatable) object. X3J11 chose
size_t to follow the *_t convention that had begun to creep up
in Posix.

HTH,

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
S

S.Tobias

Really? How? malloc() takes a size_t as an argument, so you can't
malloc() anything bigger. And if you can't take sizeof(struct foo),
it isn't necessary for it to allow your declaration of struct foo
that exceeds the limits of a size_t. The same applies to large arrays.

I don't understand. Where exactly is it written that `size_t' must
be able to cover sizes of all types? All I can find is that `size_t'
is the type returned by `sizeof' operator. Does it mean that
implementations must forbid types whose size cannot be taken?
Is it a CV, or UB?

As for allocated objects, you can't create an object larger than
SIZE_MAX with malloc(). But an implementation might have its own
allocation function:
void *hugealloc(unsigned long hi, unsigned long lo);
Would such an implementation be non-conforming?
 
P

pete

S.Tobias wrote:
I don't understand. Where exactly is it written that `size_t' must
be able to cover sizes of all types? All I can find is that `size_t'
is the type returned by `sizeof' operator. Does it mean that
implementations must forbid types whose size cannot be taken?

N869
6.5.3.4 The sizeof operator
[#2] The sizeof operator yields the size (in bytes) of its
operand, which may be an expression or the parenthesized
name of a type

If the size cannot be taken, then how can sizeof do
what it's supposed to do?
 
C

Clark S. Cox III

I don't understand. Where exactly is it written that `size_t' must be
able to cover sizes of all types? All I can find is that `size_t'
is the type returned by `sizeof' operator. Does it mean that
implementations must forbid types whose size cannot be taken?
Well, sizeof cannot possibly result in any value larger than SIZE_MAX,
and sizeof has to work with any type, it logically follows that no type
can require more than SIZE_MAX bytes.

Is it a CV, or UB?
I too can't tell if it would be a CV or UB. I wonder if a conforming
implementation would be required to issue a diagnostic on the following
structure:

struct Foo
{
char array1[SIZE_MAX];
char array2[SIZE_MAX];
char array3[SIZE_MAX];
};

Gcc certianly does, but I wonder if it's required to do so.

test.c:6: error: size of array ‘array1’ is too large
test.c:7: error: size of array ‘array2’ is too large
test.c:8: error: size of array ‘array3’ is too large

However, I've just noticed that if I make the size of the individual
arrays small enough for gcc, it surprisingly *does not* warn about the
structure itself, and the result of sizeof seems to have wrapped around
as unsigned integers are wont to do):

[littleclark2:~] clarkcox% cat test.c
#include <stdlib.h>
#include <stdio.h>

struct Foo
{
char array1[SIZE_MAX / 2];
char array2[SIZE_MAX / 2];
char array3[SIZE_MAX / 2];
};

int main()
{
printf("SIZE_MAX: %zd\nsizeof(struct Foo): %zd\n", (size_t)SIZE_MAX,
sizeof(struct Foo));
return 0;
}
[littleclark2:~] clarkcox% gcc test.c -ansi -pedantic
[littleclark2:~] clarkcox% ./a.out
SIZE_MAX: 4294967295
sizeof(struct Foo): 2147483645
[littleclark2:~] clarkcox%

This seems dangerous to my mind. Someone attempting to do the following
allocation:

strict Foo *foo = malloc(sizeof *foo);

may find that malloc "succeeds", but only allocates about 1/3 of the
memory required to contain an instance of struct Foo.


As for allocated objects, you can't create an object larger than
SIZE_MAX with malloc(). But an implementation might have its own
allocation function:
void *hugealloc(unsigned long hi, unsigned long lo);
Would such an implementation be non-conforming?

No need to look to a hypothetical implementation, I would imagine that
such a situation could arise with calloc (assuming that it doesn't
return NULL, which seems exceedingly likely on sane implementations):

calloc(2, SIZE_MAX);

Either way, the result has a type of (void*), and there is no way to
apply sizeof to what it points to.
 
S

S.Tobias

N869
6.5.3.4 The sizeof operator
[#2] The sizeof operator yields the size (in bytes) of its
operand, which may be an expression or the parenthesized
name of a type
If the size cannot be taken, then how can sizeof do
what it's supposed to do?

So what should a compiler do? Should it reject the code which
contains a declaration of type that is too large, or is it UB
applying `sizeof' to such type?
 
R

Robert Gamble

Clark said:
I don't understand. Where exactly is it written that `size_t' must be
able to cover sizes of all types? All I can find is that `size_t'
is the type returned by `sizeof' operator. Does it mean that
implementations must forbid types whose size cannot be taken?
Well, sizeof cannot possibly result in any value larger than SIZE_MAX,
and sizeof has to work with any type, it logically follows that no type
can require more than SIZE_MAX bytes.

Is it a CV, or UB?
I too can't tell if it would be a CV or UB. I wonder if a conforming
implementation would be required to issue a diagnostic on the following
structure:

struct Foo
{
char array1[SIZE_MAX];
char array2[SIZE_MAX];
char array3[SIZE_MAX];
};

Gcc certianly does, but I wonder if it's required to do so.

test.c:6: error: size of array 'array1' is too large
test.c:7: error: size of array 'array2' is too large
test.c:8: error: size of array 'array3' is too large

See Defect Report #266 entitled "overflow of sizeof" which discusses
just this scenerio using the similiar example:

char x [SIZE_MAX / 2][SIZE_MAX / 2];
size_t s = sizeof x;

The committe response was that there are multiple acceptable
interpretations of the produced behavior and that:

"The program is not strictly conforming because it exceeds an
environmental limit. If the implementation generates code, there is no
requirement for a diagnostic. In the event that sizeof is called on the
object, a diagnostic can be issued, but is not required."

You can find the full report at:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_266.htm

Robert Gamble
 
P

pete

S.Tobias said:
N869
6.5.3.4 The sizeof operator
[#2] The sizeof operator yields the size (in bytes) of its
operand, which may be an expression or the parenthesized
name of a type
If the size cannot be taken, then how can sizeof do
what it's supposed to do?

So what should a compiler do? Should it reject the code which
contains a declaration of type that is too large, or is it UB
applying `sizeof' to such type?

My compiler accepts the oversized declaration,
I just can't use it anywhere.

When I uncomment array_5, i get:
new.c(11) : error C2089: 'structure' : 'struct' too large

/* BEGIN new.c */

#include <stdio.h>

struct structure {
char array_0[(size_t)-1 / 5];
char array_1[(size_t)-1 / 5];
char array_2[(size_t)-1 / 5];
char array_3[(size_t)-1 / 5];
char array_4[(size_t)-1 / 5];
/* char array_5[(size_t)-1 / 5];*/
};

int main(void)
{
printf("sizeof(array) is %lu\n",
(long unsigned)sizeof(struct structure));
return 0;
}

/* END new.c */
 
R

Randy Howard

S.Tobias said:
pete said:
S.Tobias wrote:

I don't understand. Where exactly is it written that `size_t' must
be able to cover sizes of all types? All I can find is that `size_t'
is the type returned by `sizeof' operator. Does it mean that
implementations must forbid types whose size cannot be taken?
N869
6.5.3.4 The sizeof operator
[#2] The sizeof operator yields the size (in bytes) of its
operand, which may be an expression or the parenthesized
name of a type
If the size cannot be taken, then how can sizeof do
what it's supposed to do?

So what should a compiler do? Should it reject the code which
contains a declaration of type that is too large, or is it UB
applying `sizeof' to such type?

My compiler accepts the oversized declaration,
I just can't use it anywhere.

When I uncomment array_5, i get:
new.c(11) : error C2089: 'structure' : 'struct' too large

/* BEGIN new.c */

#include <stdio.h>

struct structure {
char array_0[(size_t)-1 / 5];

So you have -1, cast to an unsigned (and probably very large) value, then
divided by 5, yielding a still quite large value. Several such arrays
are probably far too large for your implementation to handle this way,
regardless of size_t. Try just putting in

char array_0[1000000];
and repeat that five times and watch what happens. More than a few
compilers will cough up blood on the first one.

This is a different limitation, as there is no guarantee that you
can statically declare arrays which add up to the max value for
size_t, if that's what you are trying to achieve by having five of
them.

Imagine you did manage to consume all of "size_t's range" with
arrays of char, where would your code run?
 
C

Christian Bau

"S.Tobias said:
N869
6.5.3.4 The sizeof operator
[#2] The sizeof operator yields the size (in bytes) of its
operand, which may be an expression or the parenthesized
name of a type
If the size cannot be taken, then how can sizeof do
what it's supposed to do?

So what should a compiler do? Should it reject the code which
contains a declaration of type that is too large, or is it UB
applying `sizeof' to such type?

It doesn't say anywhere that it is undefined behavior. 6.5.3.4 clearly
says what the compiler has to do. If the compiler cannot do what it has
to do, then it should better tell the user.

(The correct solution is for the compiler not to allow the definition of
any type that is so large that sizeof cannot yield the correct result as
required).
 
P

pete

Imagine you did manage to consume all of "size_t's range" with
arrays of char, where would your code run?

The question is
"Should it reject the code which contains a declaration
of type that is too large, or is it UB applying `sizeof' to such type?"

My compiler allows the declaration, but not the usage of the type.

I don't really know what a compiler is supposed to do
with an oversized declaration.
 
P

pete

Christian said:
S.Tobias said:
pete said:
S.Tobias wrote:

I don't understand. Where exactly is it written that `size_t' must
be able to cover sizes of all types? All I can find is that `size_t'
is the type returned by `sizeof' operator. Does it mean that
implementations must forbid types whose size cannot be taken?
N869
6.5.3.4 The sizeof operator
[#2] The sizeof operator yields the size (in bytes) of its
operand, which may be an expression or the parenthesized
name of a type
If the size cannot be taken, then how can sizeof do
what it's supposed to do?

So what should a compiler do? Should it reject the code which
contains a declaration of type that is too large, or is it UB
applying `sizeof' to such type?

It doesn't say anywhere that it is undefined behavior. 6.5.3.4 clearly
says what the compiler has to do.
If the compiler cannot do what it has
to do, then it should better tell the user.

No.
If the compiler can't do what it is supposed to do,
then it is not a conforming C implementation.

(The correct solution is for the compiler not to allow
the definition of any type

Do you mean "declaration"?
that is so large that sizeof cannot yield the correct
result as required).

My compiler does allow such declarations.
 
S

Stan R.

Confused said:
I am curious what the origins of size_t are. I see that it is usually
typedef'd to be the native integer size of a particular machine. I
also see that routines like strncpy(char *t, const char *s, size_t n).

So, is size_t the native size of the machine or used to describe the
actual size of something (like the len of a string copy).

If it is named because it designates the size of something, then
could I still have more than 65535 bytes of something. If so why is
that called size_t.

I understand that it is just an int, but I don't understand the name.
I can have a size that is larger than an int. Perhaps I could store
the size of something in long? Wow?!?!?!

What the heck are the origins for the name?

Elvis

Wasn't it so ther would be a common size among different compilers, or
something of the sort?
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,166
Messages
2,570,901
Members
47,442
Latest member
KevinLocki

Latest Threads

Top