Why is the maximum size of the array "too large"?

I have the same impression as this answer that size_t always guaranteed by the standard to be large enough to hold the maximum possible type of this system.

However, this code is not compiled in gcc / Mingw:

 #include <stdint.h> #include <stddef.h> typedef uint8_t array_t [SIZE_MAX]; 

error: the size of the array 'array_t' is too large

I do not understand something in the standard? Is size_t allowed to be too large for this implementation? Or is this another mistake in Mingw?




EDIT: Further studies show that

 typedef uint8_t array_t [SIZE_MAX/2]; // does compile typedef uint8_t array_t [SIZE_MAX/2+1]; // does not compile 

What happens how

 #include <limits.h> typedef uint8_t array_t [LLONG_MAX]; // does compile typedef uint8_t array_t [LLONG_MAX+(size_t)1]; // does not compile 

So, now I am inclined to believe that this is a mistake in Mingw, because setting the maximum size based on the signed integer type makes no sense.

+49
c gcc mingw size-t stdint
Mar 03 '17 at 9:17
source share
5 answers

The SIZE_MAX / 2 limit is determined by the definitions of size_t and ptrdiff_t for your implementation, which select that the types ptrdiff_t and size_t have the same width.

C Standard mandates 1 that type size_t is not specified and type ptrdiff_t is signed.

The result of the difference between the two pointers will always be 2 of type ptrdiff_t. This means that in your implementation, the size of the object must be limited by PTRDIFF_MAX, otherwise the permissible difference between the two pointers cannot be represented in the ptrdiff_t type, which will lead to undefined behavior.

Thus, the value of SIZE_MAX / 2 is equal to the value of PTRDIFF_MAX. If the implementation decides that the maximum size of the object will be SIZE_MAX, then the width of the ptrdiff_t type should be increased. But it is much easier to limit the maximum size of the SIZE_MAX / 2 object, then it must have type ptrdiff_t with a greater or equal positive range than type size_t.

The standard offers these 3 comments 4 per topic.




(Quoted from ISO / IEC 9899: 201x)

1 (7.19 General definitions 2)
Types - ptrdiff_t
which is a recognized integer type of the result of subtracting two pointers; size_t
which is the unsigned integer type of the result of the sizeof operator;

2 (6.5.6 Additive operators 9)
When two pointers are subtracted, both must point to the elements of the same array object, or one after the last element of the array object; as a result, there is a difference in the indices of the two elements of the array. The size of the result is determined by the implementation, and its type (signed integer type) is ptrdiff_t defined in the header. If the result is not represented in an object of this type, the behavior is undefined.

3 (K.3.4 Integer types 3)
Extremely large sizes of objects are often a sign that the size of the object was calculated incorrectly. For example, negative numbers appear as very large positive numbers when converted to an unsigned type of type size_t. In addition, some implementations do not support objects whose maximum values ​​can be represented by size_t.

4 (K.3.4 Integer types 4)
For these reasons, it is sometimes useful to limit the size range of objects to detect programming errors. For implementations oriented to machines with large address spaces, it is recommended that RSIZE_MAX be defined as the smaller size of the largest object (or SIZE_MAX β†’ 1), even if this limit is less than the size of some legitimate but very large objects. Implementations targeting machines with small address spaces may wish to define RSIZE_MAX as SIZE_MAX, which means that there is no object size that is considered a violation of the run-time limit.

+56
03 Mar. '17 at 10:01
source share

The size_t range is guaranteed to be sufficient to hold the size of the largest object supported by the implementation. The converse is not true: you cannot create an object whose size fills the entire range of size_t .

Under such conditions, the question arises: what does SIZE_MAX mean? Largest supported object size? Or the largest value represented in size_t ? The answer is: last, i.e. SIZE_MAX is (size_t) -1 . You are not guaranteed the ability to create SIZE_MAX objects SIZE_MAX large bytes.

The reason for this is that in addition to size_t implementations must also provide ptrdiff_t , which is intended (but not guaranteed) to store the difference between two pointers pointing to the same array object. Since the ptrdiff_t type ptrdiff_t signed, implementations are faced with the following options:

  • Allow array objects of size SIZE_MAX and make ptrdiff_t wider than size_t . It must be at least one bit wider. Such ptrdiff_t can accommodate any difference between two pointers pointing to an array of size SIZE_MAX or less.

  • Allow array objects of size SIZE_MAX and use ptrdiff_t the same width as size_t . Accept the fact that subtracting a pointer can overflow and cause undefined behavior if the pointers are located farther than the SIZE_MAX / 2 elements. The language specification does not prohibit this approach.

  • Use ptrdiff_t the same width as size_t , and limit the maximum size of the array object to SIZE_MAX / 2 . Such ptrdiff_t can accommodate any difference between two pointers pointing to an array of size SIZE_MAX / 2 or less.

You are simply dealing with an implementation that has decided to follow a third approach.

+7
Mar 04 '17 at 9:31 on
source share

It is very similar to implementation-specific behavior.

I am running Mac OS here, and with gcc 6.3.0 the largest size I can compile your definition with is SIZE_MAX/2 ; with SIZE_MAX/2 + 1 it no longer compiles.

On the other hand, the witch clang 4.0.0 is the largest - SIZE_MAX/8 , and SIZE_MAX/8 + 1 breaks.

+5
Mar 03 '17 at 9:47 on
source share

First of all, size_t used to store the result of the sizeof operator. In this way, a size that can contain the "value" of SIZE_MAX . Theoretically, this should allow you to define any object with a size of SIZE_MAX .

Then, if I remember correctly, you are limited by the upper limit of system-wide resources. These are not limitations imposed by the C standard, but rather OS / environment.

Check the output of ulimit -a . You can also change the limits with ulimit -s <size> for the stack, as long as the array you define is stored on the stack. Otherwise, for global arrays, you probably need to check the allowed size in .DATA or .BSS according to your OS. So it depends on the environment (or depends on the implementation).

+1
Mar 03 '17 at 9:21
source share

Just arguing from scratch, size_t is a type that can hold the size of any object. The size of any object is limited by the width of the address bus (ignoring multiplexing and systems that can process, for example, 32 and 64-bit code, cause this "code width"). MAX_INT , which is the largest integer value, SIZE_MAX is the largest size_t value. Thus, an object of size SIZE_MAX is the entire address memory. Of course, the implementation flag, which, like an error, however, I agree that this is an error only if the actual object is allocated, whether on the stack or in global memory. (Calling malloc for this amount will fail anyway)

+1
Mar 03 '17 at 9:38 on
source share



All Articles