Есть ли какие-либо издержки для использования массивов переменной длины?

Есть ли немного служебные из использования массивов переменной длины? Размер массива мог быть передан через параметр командной строки во время выполнения? Почему это представлено, по сравнению с автоматическим и динамично выделяющее массив?

46
задан Isaac 6 March 2019 в 01:46
поделиться

4 ответа

VLA имеет некоторые накладные расходы (по сравнению с "обычным" именованным массивом, размером с время компиляции).

Во-первых, она имеет продолжительность исполнения, и все же язык предоставляет средства для получения фактического размера массива во время исполнения (используя sizeof). Это сразу же означает, что реальный размер массива должен где-то храниться. Это приводит к небольшим накладным расходам памяти на массив. Однако, так как VLA могут быть объявлены только как автоматические объекты, то таких накладных расходов памяти никто никогда не заметит. Это все равно, что объявить дополнительную локальную переменную интегрального типа.

Во-вторых, ВЛА обычно выделяется на стеке, но из-за ее переменного размера, в общем случае ее точное расположение в памяти при компиляции неизвестно. По этой причине базовая реализация обычно вынуждена реализовать ее в виде указателя на блок памяти. Это приводит к дополнительным накладным расходам памяти (на указатель), что опять-таки совершенно несущественно по причинам, описанным выше. Это также приводит к небольшим накладным расходам, так как для нахождения реального массива нам приходится считывать значение указателя. Аналогичные накладные расходы возникают и при обращении к массивам malloc-ed (а не к именованным массивам размером с компиляцию).

Поскольку размер VLA - это целое значение во время выполнения, оно, конечно же, может быть передано в качестве аргумента командной строки. VLA не имеет значения, откуда берется ее размер.

VLA были введены в виде массивов исполняемого размера с низкой стоимостью выделения/удаления. Они умещаются между "обычными" названными массивами компиляционного размера (которые имеют практически нулевые затраты на выделение/удаление, но фиксированный размер) и массивами malloc-ed (которые имеют размер исполняемого файла, но относительно высокие затраты на выделение/удаление).

VLA подчиняется [почти] тем же правилам времени жизни, что и автоматические (т.е. локальные) объекты, что означает, что в общем случае они не могут заменить malloc-ed массивы. Их применимость ограничена ситуациями, когда нужен массив быстрого исполнения с типичным автоматическим временем жизни.

43
ответ дан 26 November 2019 в 20:31
поделиться

Накладных расходов на ВЛА должно быть очень мало (в лучшем случае это должно привести к добавлению к указателю стека). Динамическое выделение требует ручного управления памятью и медленнее, чем выделение VLA на основе стека, а "автоматическое" объявление массива требует выражения времени компиляции для размера массива. Однако следует помнить, что если произойдет переполнение стека, то это приведет к неопределенному поведению, поэтому сохраняйте ВЛА относительно небольшого размера.

Размер массива можно передать через аргумент командной строки, но код для этого придется писать самому.

1
ответ дан 26 November 2019 в 20:31
поделиться

Обычно я просто бросаю апостроф, но работают ли обратные клещи? (get_user's_group)

-121--3770430-

Ваше регулярное выражение почти работает, вы просто забыли уйти от периода. Кроме того, в PHP нужны разделители:

'/@(.*?)\./s'

S является модификатором DOTALL .

Вот полный пример того, как вы можете использовать его в PHP:

$s = 'foo@bar.baz';
$matches = array();
$t = preg_match('/@(.*?)\./s', $s, $matches);
print_r($matches[1]);

Output:

bar
-121--2300673-

Существует некоторое время выполнения накладных расходов с массивами переменной длины, но вам придется работать довольно усердно, чтобы измерить его. Обратите внимание, что sizeof (vla) не является константой времени компиляции, если vla является массивом переменной длины.

Размер массива может быть передан функции во время выполнения. Если вы выберете размер из аргумента командной строки и преобразуете его в целое число и передадите его функции во время выполнения, то так и будет - это сработает.

Массивы переменной длины используются, так как переменные автоматически присваиваются правильному размеру и автоматически освобождаются при выходе из функции. Это позволяет избежать чрезмерного выделения пространства (выделение достаточного пространства для максимально возможного размера при работе с минимальными размерами) и избежать проблем с очисткой памяти.

Кроме того, с многомерными массивами AFAIK он ведет себя скорее как Fortran - можно динамически настраивать все измерения, а не привязываться к фиксированным размерам для всех, кроме ведущего измерения массива.


Конкретные доказательства некоторых временных накладных расходов для VLA - по крайней мере, с GCC 4.4.2 на SPARC (Solaris 10).

Рассмотрим два следующих файла:

vla.c - использование массива переменной длины

#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);

size_t identity_matrix(int n, int m)
{
    int vla[n][m];
    int i, j;
    assert(n > 0 && n <= 32);
    assert(m > 0 && m <= 32);
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            vla[i][j] = 0;
        }
        vla[i][i] = 1;
    }
    return(sizeof(vla));
}

fla.c - использование массива фиксированной длины

#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);

size_t identity_matrix(int n, int m)
{
    int fla[32][32];
    int i, j;
    assert(n > 0 && n <= 32);
    assert(m > 0 && m <= 32);
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            fla[i][j] = 0;
        }
        fla[i][i] = 1;
    }
    return(sizeof(fla));
}

Компиляция и размеры файлов объектов

Для сравнения имена локального массива различны ( vla vs fla ), а размеры массива различаются при его объявлении - в противном случае файлы

Я скомпилировал с помощью:

$ gcc -O2 -c -std=c99 fla.c vla.c

Размеры файлов объектов несколько отличаются - как измеряются как «ls», так и «size»:

$ ls -l fla.o vla.o
-rw-r--r--   1 jleffler rd          1036 Jan  9 12:13 fla.o
-rw-r--r--   1 jleffler rd          1176 Jan  9 12:13 vla.o
$ size fla.o vla.o
fla.o: 530 + 0 + 0 = 530
vla.o: 670 + 0 + 0 = 670

Я не сделал обширного тестирования, чтобы увидеть, сколько накладных расходов фиксировано, а сколько переменно, но есть накладные расходы при использовании VLA.

28
ответ дан 26 November 2019 в 20:31
поделиться

Мне просто интересно, есть ли накладные расходы на использование массивов переменной длины?

Нету

Может ли размер массива можно пропустить через аргумент командной строки во время выполнения?

Да.

Почему он вводится по сравнению с автоматическим и динамически распределением массива?

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

Динамически распределение ( malloc ) будет хранить массив на куче , который имеет большое пространство памяти, но медленнее доступа.

VLA работает, размещая массив в стеке . Это делает распределение и доступ к чрезвычайно быстрым, , но стек обычно мало (из нескольких КБ), а когда VLA переполнена стека, он неотличима от бесконечной рекурсии.

4
ответ дан 26 November 2019 в 20:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: