Jump to content

    

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

Quote

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

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

Edited by GenaSPB

Share this post


Link to post
Share on other sites
12 минут назад, GenaSPB сказал:

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

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

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

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites
4 часа назад, Darth Vader сказал:

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

 

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

Share this post


Link to post
Share on other sites
1 час назад, Xenia сказал:

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

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

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

Share this post


Link to post
Share on other sites
7 часов назад, Xenia сказал:

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

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

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

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

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

Share this post


Link to post
Share on other sites
9 часов назад, Xenia сказал:

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

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

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

Share this post


Link to post
Share on other sites
30 minutes ago, jcxz said:

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

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

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

Share this post


Link to post
Share on other sites
2 часа назад, makc сказал:

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

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

Share this post


Link to post
Share on other sites
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: Я склонен считать, что в упомянутой выше документации техническая ошибка. Попробую это проверить.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites

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 в стеке.

Share this post


Link to post
Share on other sites
35 минут назад, makc сказал:

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

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

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

Share this post


Link to post
Share on other sites

Ок, возражение принимается. Попробовал в 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:

Share this post


Link to post
Share on other sites
2 часа назад, makc сказал:

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

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

Ужасно :dash2:

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now