Перейти к содержанию
    

Неконстантный размер локальных массивов - можно ли?

Quote

Memory for variable length arrays is allocated at runtime, on the heap

Какая такая куча? Процитированное немного бред. На стеке да...

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 минут назад, GenaSPB сказал:

Какая такая куча? 

Действительно, на куче... Здесь аналогичное пишут. Странно. Тогда ведь и malloc можно применить вместо VLA.

http://www.keil.com/support/man/docs/armcc/armcc_chr1359124223721.htm

Насколько я понимаю, стандартом не указано, где располагать такие массивы. В GCC действительно на стеке. Такой выбор как раз понятен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А действительно: как компилятору адресовать локальные переменные функции на стеке и аргументы функции в случае, если на стеке будет создан массив переменного размера? Ведь при выделении стека для него, регистр SP должен быть сдвинут вниз на переменную величину (определяемую в runtime), а значит адресовывать их через константное смещение относительно SP - уже не получится. А значит видимо в такой функции компилятору нужно будет сохранить начальное состояние SP (на входе в функцию) в дополнительном регистре (зарезервировать дополнительный регистр (указатель) для этого) и адресовывать аргументы функции до неё через этот регистр (и сам массив). А если таких массивов два? Тогда нужно уже два таких регистра-указателя. И т.д.

В то время как с массивами константного размера можно их все (хоть сколько их штук) адресовать через SP.

Это ещё один минус массивов переменной длины - необходимость лишних указателей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, Darth Vader сказал:

Вот ещё нашлось. Вцелом, повторяет информацию с сайта ARM. Но добавлено ещё примечание, что память под такие массивы выделяется в куче.

 

Ну так всё-таки, где им выделяется место? На стеке (stack) или в куче (heap)? А то здесь все согласно кивают головами, делая вид, что стек и куча - одно и то же. Тогда как автоматические переменные хранятся на стеке, а если в хипе, то это уже динамически аллокируемая переменная/массив. Неужели до сих пор никто так и не заглянул в код компиляции, чтобы узнать, какую память отводит компилятор под VLA-массивы? Так и будем на ромашке гадать, на разные ссылочки друг другу пальчиком показывая?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Xenia сказал:

Ну так всё-таки, где им выделяется место? На стеке (stack) или в куче (heap)?

Я вот не понял, почему обсуждение проблемы динамических массивов свелось к обсуждению места (непонятного), которое им выделяют разные компиляторы?

Почему нельзя самому жестко зафиксировать за собой место с помощью malloc (и далее new,realloc,delete,free) или других функций динамического выделения памяти?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 часов назад, Xenia сказал:

Ну так всё-таки, где им выделяется место?

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

5 часов назад, V_G сказал:

Я вот не понял, почему обсуждение проблемы динамических массивов свелось к обсуждению места (непонятного), которое им выделяют разные компиляторы?

По-моему проблема вообще не стоит обсуждения, т.к. найти ответы на все вопросы можно за 5 минут поиска в Гугле и чтения Wiki/описаний конкретного компилятора. Ссылки даны выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 часов назад, Xenia сказал:

Неужели до сих пор никто так и не заглянул в код компиляции, чтобы узнать, какую память отводит компилятор под VLA-массивы?

Видимо те, кто  их использует (VLA), никогда не заглядывают в листинги.Не умеют просто. А те кто заглядывает, и задумывается о качестве результирующего кода, те не используют VLA.  :yes3:

Недавно был тред о необходимости "заглядывания в листинги". Очень показательный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

30 minutes ago, jcxz said:

А те кто заглядывает, и задумывается о качестве результирующего кода, те не используют VLA. 

Только здравый смысл и пониманием работы компилятора запрещает использовать этот VLA там, где ему не место.

Глядеть для этого в листинги вовсе необязательно )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, makc сказал:

Как и другие локальные переменные - в стеке.

Вы забыли дописать "обычно". Потому что в справке на конкретный обсуждаемый компилятор (на которую выше давались ссылки) явно сказано, что именно он выделяет в куче.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 минут назад, Сергей Борщ сказал:

Вы забыли дописать "обычно". Потому что в справке на конкретный обсуждаемый компилятор (на которую выше давались ссылки) явно сказано, что именно он выделяет в куче. 

Согласен, но пока я не видел ни одного примера описанного поведения. Хотя, естественно, это мало о чем говорит, т.к. в стандарте C нет понятия "стек" и поэтому апеллировать к стандарту не получится, что открывает возможность разработчикам сделать это по-своему. Но с другой стороны управление кучей отдано на откуп системной библиотеке и по факту является специфичным для проекта, т.к. мы для себя используем свой malloc (да и реализаций этого malloc есть довольно много разных и они по определению несовместимы):

Цитата

7.20.3 Memory management functions
The order and contiguity of storage allocated by successive calls to the calloc,
malloc, and realloc functions is unspecified. The pointer returned if the allocation
succeeds is suitably aligned so that it may be assigned to a pointer to any type of object
and then used to access such an object or an array of such objects in the space allocated
(until the space is explicitly freed or reallocated). Each such allocation shall yield a
pointer to an object disjoint from any other object.

Кроме того такое размещение VLA в куче дает лишние бинарные зависимости. Таким образом получается, что использование массивов переменной длины, размещаемых в куче, может очень интересным образом сломать проект, подтянув дополнительный malloc из библиотеки компилятора в дополнение к уже используемому собственному malloc'у.

PS: Я склонен считать, что в упомянутой выше документации техническая ошибка. Попробую это проверить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 часов назад, V_G сказал:

Я вот не понял, почему обсуждение проблемы динамических массивов свелось к обсуждению места (непонятного), которое им выделяют разные компиляторы?

Почему нельзя самому жестко зафиксировать за собой место с помощью malloc (и далее new,realloc,delete,free) или других функций динамического выделения памяти?

Потому что динамически из хипа аллокировать массивы вы всегда могли (это параметр у malloc), и для этого никакой VLA не нужен. Тогда как VLA может быть интересен только в том случае, если он способен выделять место массиву на стеке. Отсюда и вопросы про VLA - откуда он выделяет память под массивы? Если динамически из хипа, то нафиг он тогда нужен, а если из стека, то тогда это полезный инструмент.

 

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

 

 

7 часов назад, makc сказал:

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

Именно ради этого я и просила в тот ассемблерный листинг заглянуть. И свой комментарий по поводу сообщения Darth Vader'а написала потому, что в ссылке, которую он дал,  было написано: "Memory for variable length arrays is allocated at runtime, on the heap." (ARM Keil). После этого бодания на тему, чья ссылка лучше, перестали иметь смысл, и оставалось только одно - проверить, как поступает в этих случаях каждый конкретный компилятор. Ваш ответ я тоже не могу принять, поскольку вы умолчали о том, каким компилятором пользовались. Вдруг у вас Keil?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

По теме.

2 часа назад, Xenia сказал:

Вдруг у вас Keil?

Нет, у меня gcc разных версий и мне его хватает на все 100%.

Попробовал скомпилировать простой исходник в ARM Compiler 6.5:

Спойлер

#include <string.h>

int f(int n)
{
	int a[n];
	memset(a, 0, sizeof(a));
	return a[0] + a[1];
}

 

И вот что получилось:

Спойлер

f:
	.fnstart
@ BB#0:
	.save	{r4, r6, r7, lr}
	push	{r4, r6, r7, lr}
	.setfp	r7, sp, #8
	add	r7, sp, #8
	.pad	#24
	sub	sp, #24
	mov	r1, r0
	str	r0, [r7, #-12]
	mov	r2, sp
	str	r2, [r7, #-16]
	movs	r2, #7
	add.w	r2, r2, r0, lsl #2
	bic	r2, r2, #7
	mov	r3, sp
	subs	r2, r3, r2
	mov	sp, r2
	lsls	r0, r0, #2
	str	r0, [r7, #-20]          @ 4-byte Spill
	mov	r0, r2
	ldr	r3, [r7, #-20]          @ 4-byte Reload
	str	r1, [r7, #-24]          @ 4-byte Spill
	mov	r1, r3
	str	r2, [r7, #-28]          @ 4-byte Spill
	bl	__aeabi_memclr4
	ldr	r0, [r7, #-28]          @ 4-byte Reload
	ldr	r1, [r0]
	ldr	r2, [r0, #4]
	adds	r0, r1, r2
	ldr	r1, [r7, #-16]
	mov	sp, r1
	sub.w	r4, r7, #8
	mov	sp, r4
	pop	{r4, r6, r7, pc}

 

Самое интересное кроется в строках:

	movs	r2, #7
	add.w	r2, r2, r0, lsl #2
	bic	r2, r2, #7
	mov	r3, sp
	subs	r2, r3, r2
	mov	sp, r2

Как вы можете заметить, здесь не используется выделение в куче, используется стек. При этом в стеке выделяется необходимое количество памяти и далее изменяется значение указателя стека (sp).

Так что не только gcc выделяет локальные переменные в стеке, включая и массивы переменной длины. На сколько я понимаю, в Keil MDK используется тот же компилятор ARM Compiler 6.5 и поэтому он так же должен выделять VLA в стеке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 минут назад, makc сказал:

Keil MDK используется тот же компилятор ARM Compiler 6.5

Нет, не так. 6.y основан на clang, это armclang, а 4.y, 5.y - это armcc, что-то из разработок Keil.

Поведение 6.5 с выделением на стеке, таким образом, полностью ожидаемо. Надо ждать листинга версии 5.y.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ок, возражение принимается. Попробовал в armcc 5.06:

Спойлер

; generated by Component: ARM Compiler 5.06 update 3 (build 300) Tool: armcc [4d35f0]
; commandline armcc [--thumb -c -S --vla test.c]
        THUMB
        REQUIRE8
        PRESERVE8

        AREA ||.text||, CODE, READONLY, ALIGN=1

f PROC
        PUSH     {r4-r6,lr}
        LSLS     r0,r0,#2
        MOVS     r5,r0
        BL       malloc
        MOVS     r4,r0
        MOVS     r1,r5
        BL       __aeabi_memclr4
        LDM      r4!,{r0,r1}
        ADDS     r5,r0,r1
        MOVS     r0,r4
        SUBS     r0,r0,#8
        BL       free
        MOVS     r0,r5
        POP      {r4-r6,pc}
        ENDP


        AREA ||.arm_vfe_header||, DATA, READONLY, NOALLOC, ALIGN=2

        DCD      0x00000000

        EXPORT f [CODE]

        IMPORT ||Lib$$Request$$armlib|| [CODE,WEAK]
        IMPORT malloc [CODE]
        IMPORT __aeabi_memclr4 [CODE]
        IMPORT free [CODE

 

И тут действительно вызывается malloc/free. Ужасно. :dash2:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, makc сказал:

И тут действительно вызывается malloc/free.

Спасибо большое! А то уже давно нет под рукой этих тулчейнов.

Ужасно :dash2:

P.S. Мне как-то давно говорили, что armcc основан на каком-то древнем GCC, потом у GCC сменилась лицензия, все стало совсем жёстко, в Keil продолжили пилить сами. Видимо, это как раз их собственная реализация VLA.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...