Для чего нужны массивы нулевого размера?

237
21 декабря 2018, 09:00

Подскажите, для чего они нужны?

И является ли следующий пример валидным и законным? :

int arr_1[0], 
    arr_2[0];
memset(arr_1, 0, sizeof(int) * 0);
memcpy(arr_1, arr_2, sizeof(int) * 0);

PS. Приведу более конкретный пример, где бы я хотел использовать массивы переменной длины с возможностью задания нулевого размера:

void thread_func(void *_param)
{
    const size_t di_count = ((t_param*)_param)->di_count;
    const size_t ai_count = ((t_param*)_param)->ai_count;
    uint8_t di[di_count];
    uint16_t ai[ai_count];
    while (1)
    {
        // Поддержание соединения.
        // ...
        // Известно, что (di_count || ai_count) != 0
        // Опрашиваем дискретные сигналы, если они есть.
        int d = 0;
        if (di_count > 0)
        {
            d = get_di(..., ..., di, di_count);
        }
        // Опрашиваем аналоговые сигналы, если они есть.
        int a = 0;
        if (ai_count > 0)
        {
            a = get_ai(..., ..., ai, ai_count);
        }
        // Формируем пакет с результатами опроса и добавляем его в очередь.
        pack *new_pack = create_pack(...,
                                     a || d,// Доступность объекта.
                                     di_count,
                                     di_count ? di : NULL,
                                     ai_count,
                                     ai_count ? ai : NULL);
        if (new_pack != NULL)
        {
            push_pack(..., new_pack);
        }
    }
}

Код сильно-пресильно упрощенный, но, надеюсь, моя идея ясна.

Так вообще делают? Я довольно часто встречаюсь с ситуациями, когда мне необходим массив переменного размера с возможным размером 0. Ясное дело, что в описанном случае обратиться к элементам массива нулевого размера нельзя, но я и не собираюсь, просто это значительно упрощает код.

В общем, корректно ли делать так, как я делаю?

Answer 1

И в С, и в С++ запрещено объявление массивов константного нулевого размера. Такие объявления являются ошибочными с точки зрения этих языков.

Дополнительно, в С, если в точке объявления variable length array значение размера не является положительным, то поведение не определено.

Массив нулевого размера можно разве что выделить через new[] в С++.

Объявления массивов явного нулевого размера поддерживаются некоторыми компиляторами в качестве нестандартного расширения языка для облегчения реализации "struct hack", хотя на самом деле можно прекрасно обойтись и без этого. В языке С, начиная с С99, для этой цели служит объявление массива без указания размера вообще.

Answer 2

Лично мое мнение:

int arr_1[0];

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

int* p = arr_1;
int i = 0;
while (true) {
   p += i;
   *p = ++i;
   cout << i << ' ';     
}

и после какого то шага увидеть где рушится программа, тем самым определить массив какого размера могло бы поместится по этому адресу...

Очевидно, что от этого нет никакой пользы и, к тому же, поведение может быть неопределенным.

И еще:

результат умножения любого числа и нуля будет нулем, поэтому

sizeof(int) * 0  

является лишней писаниной, которую можно просто заменить нулем...

READ ALSO
Найти количество чётных цифр в записи числа отличных от нуля

Найти количество чётных цифр в записи числа отличных от нуля

Дано целое число nТребуется найти количество четных цифр в записи этого числа отличных от нуля

198
“Attempting to use an incompatible return type” error

“Attempting to use an incompatible return type” error

Не совсем понятно почему в классе наследнике нельзя переопределить метод и изменить возвращаемый тип

193
Spring постраничный вывод из БД

Spring постраничный вывод из БД

Есть небольшое CRUD приложениеПодскажите как лучше реализовать постраничный вывод данных из БД? Контролер:

215