Участник:Joparino/Массив переменной длины: различия между версиями
Joparino (обсуждение | вклад) Нет описания правки |
Joparino (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
В [[Программирование|программировании]] '''массив переменной длины''' ({{lang-en|variable-length array, VLA}}), также называемый '''variable-sized''' или '''runtime-sized''', представляет собой [[Массив (тип данных)|массивом]], длина которого определяется во время выполнения (а не во время компиляции)<ref name=cray>{{cite web |url=http://docs.cray.com/books/004-2179-001/html-004-2179-001/z893434830malz.html |title=Variable Length Arrays |archiveurl=https://web.archive.org/web/20180126153326/http://docs.cray.com/books/004-2179-001/html-004-2179-001/z893434830malz.html |archivedate=2018-01-26 |url-status=dead}}</ref>. |
В [[Программирование|программировании]] '''массив переменной длины''' ({{lang-en|variable-length array, VLA}}), также называемый {{lang-en|'''variable-sized'''}} или {{lang-en|'''runtime-sized'''}}, представляет собой [[Массив (тип данных)|массивом]], длина которого определяется во время выполнения (а не во время компиляции)<ref name=cray>{{cite web |url=http://docs.cray.com/books/004-2179-001/html-004-2179-001/z893434830malz.html |title=Variable Length Arrays |archiveurl=https://web.archive.org/web/20180126153326/http://docs.cray.com/books/004-2179-001/html-004-2179-001/z893434830malz.html |archivedate=2018-01-26 |url-status=dead}}</ref>. |
||
В C массив переменной длины имеет изменяемый тип, который зависит от значения (см. [[Зависимый тип]]). |
В C массив переменной длины имеет изменяемый тип, который зависит от значения (см. [[Зависимый тип]]). |
||
Версия от 11:10, 13 августа 2022
В программировании массив переменной длины (англ. variable-length array, VLA), также называемый англ. variable-sized или англ. runtime-sized, представляет собой массивом, длина которого определяется во время выполнения (а не во время компиляции)[1]. В C массив переменной длины имеет изменяемый тип, который зависит от значения (см. Зависимый тип).
Основная цель массивов переменной длины — это упростить программирование численных алгоритмов.
Языки программирования, поддерживающие массивы переменной длины: Ada, Algol 68 (для негибких строк), APL, C99 (хотя впоследствии он был отнесен в C11 к условной функции, для поддержки которой реализации не требуются[2][3]; на некоторых платформах может быть реализован ранее с помощью alloca()
или аналогичных функций) и C# (как массивы, выделенные стеком в небезопасном режиме), COBOL, Fortran 90, J, и Object Pascal (язык, используемый в Borland Delphi и Lazarus, использующий FPC).
Память
Распределение памяти
- GNU C Compiler выделяет память для массива переменной длины с автоматическим сроком хранения (англ. automatic storage duration) в стеке[4]. Это более быстрый и простой вариант по сравнению с выделением кучи, и он используется большинством компиляторов.
- Массив переменной длины также могут быть выделены в куче и внутренне доступны с помощью указателя на этот блок.
Реализация
C99
Следующая функция C99 выделяет массив переменной длины заданного размера, заполняет его значениями с плавающей запятой, а затем передает его другой функции для обработки. Из-за того, что массив объявлен как автоматическая переменная, его время жизни заканчивается, когда возвращается read_and_process()
.
float read_and_process(int n)
{
float vals[n];
for (int i = 0; i < n; ++i)
vals[i] = read_val();
return process(n, vals);
}
В C99 параметр длины должен предшествовать параметру массива переменной длины при вызовах функций[1]. В C11 определяется макрос __STDC_NO_VLA__
, если массив переменной длины не поддерживается[5]. GCC имел массив переменно длины в качестве расширения до C99, которое также распространяется на его диалект C++.
Линус Торвальдс в прошлом выражал свое недовольство использованием массива переменной длины для массивов с заранее заданными малыми размерами, поскольку это порождает ассемблерный код более низкого качества[6]. С Linux 4.20 ядро Linux фактически не содержит массивов переменной длины[7].
Хотя C11 явно не указывает ограничение по размеру для массивов переменной длины, некоторые читатели считают, что он должен иметь тот же максимальный размер, что и все другие объекты, т.е. SIZE_MAX байт[8]. Однако это значение следует понимать в более широком контексте ограничений среды и платформы, таких как типичный размер страницы с защитой стека 4 КБ, что на много порядков меньше, чем SIZE_MAX.
Можно иметь синтаксис, подобный массиву переменной длины, с динамическим хранением с помощью указателя на массив.
float read_and_process(int n)
{
float (*vals)[n] = malloc(sizeof(float[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = read_val();
float ret = process(n, *vals);
free(vals);
return ret;
}
Ada
Ниже приведен тот же пример в Ada. Массивы в Ada несут свои границы вместе с ними, поэтому нет необходимости передавать их длину функции Process.
type Vals_Type is array (Positive range <>) of Float;
function Read_And_Process (N : Integer) return Float is
Vals : Vals_Type (1 .. N);
begin
for I in 1 .. N loop
Vals (I) := Read_Val;
end loop;
return Process (Vals);
end Read_And_Process;
Fortran 90
Эквивалентная функция Fortran 90 является
function read_and_process(n) result(o)
integer,intent(in)::n
real::o
real,dimension(n)::vals
integer::i
do i = 1,n
vals(i) = read_val()
end do
o = process(vals)
end function read_and_process
при использовании функции Fortran 90 проверки интерфейсов процедур во время компиляции; с другой стороны, если функции используют интерфейс вызова до Fortran 90, сначала должны быть объявлены (внешние) функции, а длина массива должна быть явно передана в качестве аргумента (как в C):
function read_and_process(n) result(o)
integer,intent(in)::n
real::o
real,dimension(n)::vals
real::read_val, process
integer::i
do i = 1,n
vals(i) = read_val()
end do
o = process(vals,n)
end function read_and_process
Cobol
Следующий фрагмент COBOL объявляет массив записей переменной длины DEPT-PERSON
, имеющий длину (количество элементов), заданную значением PEOPLE-CNT
:
DATA DIVISION.
WORKING-STORAGE SECTION.
01 DEPT-PEOPLE.
05 PEOPLE-CNT PIC S9(4) BINARY.
05 DEPT-PERSON OCCURS 0 TO 20 TIMES DEPENDING ON PEOPLE-CNT.
10 PERSON-NAME PIC X(20).
10 PERSON-WAGE PIC S9(7)V99 PACKED-DECIMAL.
Массивы переменной длины в COBOL, в отличие от других языков, упомянутых здесь, безопасен, потому что COBOL требует указания максимального размера массива — в этом примере DEPT-PERSON
не может содержать более 20 элементов, независимо от значения PEOPLE-CNT
.
C#
Следующий фрагмент C# объявляет массив целых чисел переменной длины. До версии C# 7.2 требуется указатель на массив, что требует "небезопасного" контекста. Ключевое слово "unsafe" требует, чтобы сборка, содержащая этот код, была помечена как небезопасная.
unsafe void DeclareStackBasedArrayUnsafe(int size)
{
int *pArray = stackalloc int[size];
pArray[0] = 123;
}
C# версии 7.2 и более поздних версий позволяют выделять массив без ключевого слова "unsafe" с помощью функции Span[9].
void DeclareStackBasedArraySafe(int size)
{
Span<int> stackArray = stackalloc int[size];
stackArray[0] = 123;
}
Object Pascal
В этом языке массив переменной длины называется динамическим массивом. Объявление такой переменной аналогично объявлению статического массива, но без указания его размера. Размер массива задается во время его использования.
program CreateDynamicArrayOfNumbers(Size: Integer);
var
NumberArray: array of LongWord;
begin
SetLength(NumberArray, Size);
NumberArray[0] := 2020;
end.
Удаление содержимого динамического массива выполняется путем присвоения ему нулевого размера.
...
SetLength(NumberArray, 0);
...
Ссылки
- ↑ 1 2 Variable Length Arrays . Архивировано из оригинала 26 января 2018 года.
- ↑ Variable Length – Using the GNU Compiler Collection (GCC) .
- ↑ ISO 9899:2011 Programming Languages – C 6.7.6.2 4.
- ↑ Code Gen Options - The GNU Fortran Compiler .
- ↑ § 6.10.8.3 of the C11 standard (n1570.pdf)
- ↑ LKML: Linus Torvalds: Re: VLA removal (was Re: [RFC 2/2] lustre: use VLA_SAFE) . lkml.org.
- ↑ The Linux Kernel Is Now VLA-Free: A Win For Security, Less Overhead & Better For Clang - Phoronix (англ.). www.phoronix.com.
- ↑ §6.5.3.4 and §7.20.3 of the C11 standard (n1570.pdf)
- ↑ stackalloc operator (C# reference) . Microsoft.