Какой максимальный размер массива в C?

Я понимаю, что аппаратное обеспечение будет ограничивать объем памяти, выделяемой во время выполнения программы. Однако мой вопрос не касается аппаратного обеспечения. Предполагая, что не было никакого ограничения на объем памяти, не будет ли никакого ограничения для массива?

7 ответов

Решение

Не существует фиксированного ограничения на размер массива в C.

Размер любого отдельного объекта, в том числе любого объекта массива, ограничен SIZE_MAXмаксимальное значение типа size_t, который является результатом sizeof оператор. (Не совсем ясно, разрешает ли стандарт C объекты размером больше SIZE_MAX байты, но на практике такие объекты не поддерживаются; см. сноску.) С SIZE_MAX определяется реализацией и не может быть изменена какой-либо программой, которая накладывает верхнюю границу SIZE_MAX байты для любого отдельного объекта. (Это верхняя граница, а не в последнюю очередь верхняя граница; реализации могут и обычно накладывают меньшие ограничения.)

Ширина типа void*, тип общего указателя, накладывает верхнюю границу на общий размер всех объектов в исполняемой программе (который может быть больше, чем максимальный размер отдельного объекта).

Стандарт C накладывает нижние, но не верхние границы на эти фиксированные размеры. Никакая соответствующая реализация C не может поддерживать объекты бесконечного размера, но в принципе она может поддерживать объекты любого конечного размера. Верхние границы устанавливаются отдельными реализациями C, средами, в которых они работают, и физикой, а не языком.

Например, соответствующая реализация может иметь SIZE_MAX равно 21024-1, что означает, что в принципе может иметь объекты до 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 байт.

Удачи в поиске оборудования, которое на самом деле поддерживает такие объекты.

Сноска. Нет явного правила, согласно которому ни один объект не может быть больше SIZE_MAX байт. Вы не могли бы с пользой применить sizeof оператор для такого объекта, но, как и любой другой оператор, sizeof может переполниться; это не значит, что вы не можете выполнять операции с таким объектом. Но на практике любая вменяемая реализация сделает size_t достаточно большой, чтобы представить размер любого объекта, который он поддерживает.

C99 5.2.4.1 "Пределы перевода" минимальный размер

Реализация должна иметь возможность переводить и выполнять по крайней мере одну программу, которая содержит по крайней мере один экземпляр каждого из следующих ограничений: 13)

  • 65535 байт в объекте (только в размещенной среде)

13) Реализации должны по возможности избегать введения фиксированных лимитов перевода.

Это говорит о том, что соответствующая реализация может отказаться от компиляции объекта (который включает в себя массивы) с более чем short байт.

PTRDIFF_MAXкажется практическим ограничением для статических объектов массива

Стандарт C99 6.5.6 Аддитивные операторы гласят:

9 Когда вычтены два указателя, оба должны указывать на элементы одного и того же объекта массива или один за последним элементом последнего объекта массива; Результатом является разница индексов двух элементов массива. Размер результата определяется реализацией, а его тип (целочисленный тип со знаком) ptrdiff_t определены в <stddef.h> заголовок. Если результат не может быть представлен в объекте этого типа, поведение не определено.

Что подразумевает для меня, что массивы больше, чем ptrdiff_t разрешены в теории, но тогда вы не можете переносить разницу их адресов.

Так что, возможно, по этой причине, GCC просто ограничивает вас ptrdiff_t, Это также упоминается в: Почему максимальный размер массива "слишком большой"?

Я эмпирически подтвердил это с main.c:

#include <stdint.h>

uint8_t a[(X)];

int main(void) {
    return 0;
}

а затем в Убунбу 17.10:

$ arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Ubuntu/Linaro 7.2.0-6ubuntu1) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ printf '
> #include <stdint.h>
> PTRDIFF_MAX
> SIZE_MAX
> ' | arm-linux-gnueabi-cpp | tail -n2
(2147483647)
(4294967295U)
$ PTRDIFF_MAX == 2147483647 == 2^31 - 1
$
$ # 2lu << 30 == 2^31 == PTRDIFF_MAX + 1
$ arm-linux-gnueabi-gcc -std=c99 -DX='(2lu << 30)' main.c
a.c:5:9: error: size of array ‘a’ is too large
 uint8_t a[(X)];
         ^
$
$ # PTRDIFF_MAX
$ arm-linux-gnueabi-gcc -std=c99 -DX='(2lu << 30) - 1lu' main.c
$

Смотрите также

64-битная машина теоретически может адресовать максимум 2^64 байта памяти.

Без учета памяти максимальный размер массива ограничен типом целого числа, используемого для индексации массива.

Размер указателя ограничит доступ к памяти. Даже если оборудование предлагает поддержку неограниченного объема памяти, если самый большой тип данных, который вы можете использовать, является 64-битным, вы сможете получить доступ только к 2^64 байтам памяти.

Я предполагаю, что самым большим теоретическим массивом будет максимальное значение "unsigned long" (или любое большее целое число, которое поддерживает последний стандарт / ваш компилятор)

Я искал способ определить максимальный размер для массива. Этот вопрос, кажется, задает то же самое, поэтому я хочу поделиться своими выводами.

Первоначально C не предоставляет никакой функции для определения максимального количества элементов, выделяемых в массиве во время компиляции. Это потому, что это будет зависеть от объема памяти, доступной на компьютере, где он будет выполняться.

С другой стороны, я обнаружил, что функции выделения памяти (calloc() а также malloc()) позволяют размещать большие массивы. Кроме того, эти функции позволяют обрабатывать ошибки выделения памяти во время выполнения.

Надеюсь, это поможет.

Другие вопросы по тегам