Просто любопытно, что на самом деле произойдет, если я определю int array[0];
в коде массив нулевой длины ? GCC вообще не жалуется.
Пример программы
#include <stdio.h>
int main() {
int arr[0];
return 0;
}
осветление
На самом деле я пытаюсь выяснить, оптимизированы ли массивы нулевой длины, инициализированные таким образом, вместо того, чтобы указывать на переменную длину в комментариях Дархазера или нет.
Это потому, что мне нужно выпустить некоторый код в дикую природу, поэтому я пытаюсь выяснить, нужно ли мне обрабатывать случаи, когда SIZE
определяется как 0
, что происходит в некотором коде со статически определеннымint array[SIZE];
Я был действительно удивлен, что GCC не жалуется, что привело к моему вопросу. Судя по полученным мной ответам, я считаю, что отсутствие предупреждения в значительной степени связано с поддержкой старого кода, который не был обновлен с использованием нового синтаксиса [].
Поскольку меня в основном интересовала ошибка, я помечаю ответ Lundin как правильный (Nawaz был первым, но он не был таким полным) - другие указывали на его фактическое использование для структур с подбитыми хвостами, хотя и актуально, не так ли? Это именно то, что я искал.
[]
в Python или даже""
в C? Иногда у вас есть функция или макрос, для которых требуется массив, но у вас нет данных для добавления в него.Ответы:
Массив не может иметь нулевой размер.
ISO 9899: 2011 6.7.6.2:
Приведенный выше текст верен как для простого массива (параграф 1). Для VLA (массива переменной длины) поведение не определено, если значение выражения меньше или равно нулю (параграф 5). Это нормативный текст в стандарте C. Компилятору не разрешается реализовывать это иначе.
gcc -std=c99 -pedantic
дает предупреждение для случая, не связанного с VLA.источник
#error
директиву.#error
директиву препроцессора.По стандарту это не допускается.
Однако в настоящее время компиляторы C рассматривают эти объявления как объявление гибкого элемента массива ( FAM ) :
Стандартный синтаксис FAM:
Идея состоит в том, чтобы затем распределить его так:
Вы также можете использовать его статически (расширение gcc):
Это также известно как хвостовые структуры (этот термин предшествует публикации стандарта C99) или struct hack (спасибо Джо Врешнигу за указание на это).
Однако этот синтаксис был стандартизирован (и эффекты гарантированы) только недавно в C99. Раньше требовался постоянный размер.
1
был портативным способом, хотя и довольно странным.0
лучше указывал намерение, но не было законным в отношении Стандарта и поддерживалось как расширение некоторыми компиляторами (включая gcc).Однако практика заполнения хвоста основана на том, что хранилище доступно (осторожно
malloc
), поэтому в целом не подходит для использования стека.источник
int content[];
насколько я понимаю, здесь подходит . Поскольку я не слишком разбираюсь в терминах C в этом искусстве ... не могли бы вы подтвердить, что мои рассуждения кажутся правильными?foo[x]
чтобыfoo[0]
каждый раз , когдаfoo
был массив с одним элементом.В Стандартных C и C ++ массив нулевого размера не допускается.
Если вы используете GCC, скомпилируйте его с помощью
-pedantic
option. Он предупредит , говоря:В случае C ++ выдает аналогичное предупреждение.
источник
error C2466: cannot allocate an array of constant size 0
[BCC32 Error] test.c(3): E2021 Array must have at least one element
-pedantic -Werror
вы могли бы просто сделать-pedantic-errors
std::array
. (Кроме того: я помню, но не могу найти источник, в котором VLA были рассмотрены и явно отклонены из-за того, что они находятся на C ++.)Это абсолютно незаконно, и всегда было так, но многие компиляторы не сообщают об ошибке. Я не уверен, почему вы хотите это сделать. Единственное использование, которое я знаю, - это вызвать ошибку времени компиляции из логического:
Если
condition
ложно, то я получаю ошибку времени компиляции. Однако, поскольку компиляторы позволяют это, я стал использовать:Это дает размер либо 1, либо -1, и я никогда не встречал компилятора, который принимал бы размер -1.
источник
STATIC_ASSERT
использовали его.#if condition \n #error whatever \n #endif
Добавлю, что есть целая страница по этому аргументу онлайн-документации gcc.
Некоторые цитаты:
и
чтобы ты мог
и бум :-)
источник
int a[0]
, тоa[0] = 1
a[1] = 2
??a[100000] = 5
но если вам повезет, вы просто разобьете свое приложение, если вам повезет: -)Еще одно использование массивов нулевой длины - создание объектов переменной длины (до C99). Нулевая длина массивы являются различными из гибких массивов , которые имеют [] без 0.
Цитата из документа gcc :
Реальный пример - это массивы нулевой длины
struct kdbus_item
в kdbus.h (модуль ядра Linux).источник
void*
арифметические (поэтому добавление или вычитание указателей на объекты нулевого размера было бы запрещено). Хотя гибкие элементы массива в основном лучше массивов нулевого размера, они также могут действовать как своего рода «объединение» для псевдонимов, не добавляя дополнительного уровня «синтаксического» косвенного обращения к тому, что следует (например, еслиstruct foo {unsigned char as_bytes[0]; int x,y; float z;}
можно получить доступ к элементамx
..z
...myStruct.asFoo.x
, и т. д. Кроме того, IIRC, C кричит при любых усилиях по включению гибкого элемента массива в структуру, что делает невозможным наличие структуры, которая включает в себя несколько других элементов гибкого массива известной длины содержание.sizeof x->contents
является ошибкой в ISO C, а не возвращением 0 в gcc. Массивы нулевого размера, не являющиеся членами структуры, создают множество других проблем.struct {int n; THING dat[];}
и может работать с объектами статической или автоматической продолжительности.Объявления массивов нулевого размера внутри структур были бы полезны, если бы они были разрешены, и если бы семантика была такой, что (1) они принудительно выравнивали, но в противном случае не выделяли никакого места, и (2) индексирование массива считалось бы определенным поведением в случай, когда результирующий указатель будет в том же блоке памяти, что и структура. Такое поведение никогда не было разрешено ни одним стандартом C, но некоторые старые компиляторы допускали это до того, как стало стандартом для компиляторов разрешать неполные объявления массивов с пустыми скобками.
Взлом структуры, обычно реализуемый с использованием массива размером 1, является изворотливым, и я не думаю, что компиляторы должны воздерживаться от его нарушения. Например, я ожидал бы, что если компилятор увидит
int a[1]
, он будет вправе рассматриватьa[i]
какa[0]
. Если кто-то пытается обойти проблемы с выравниванием структуры взлома с помощью чего-то вродекомпилятор может сообразить и предположить, что размер массива действительно равен четырем:
Такая оптимизация может быть разумной, особенно если ее
myStruct->data
можно загрузить в регистр в той же операции, что иmyStruct->size
. Я не знаю ничего в стандарте, который запрещал бы такую оптимизацию, хотя, конечно, это нарушило бы любой код, который мог ожидать доступа к материалам за пределами четвертого элемента.источник