реклама на сайте
подробности

 
 
> Динамическое размещение буфера в функции, Если размер изначально неизвестен...
KnightIgor
сообщение Dec 27 2012, 10:40
Сообщение #1


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Привет всем.

Бывает, что на этапе компиляции размер требуемого буфера внутри функции точно неизвестен. В этом случае используют либо динамическое размещение памяти (malloc), что тянет за собой всю поддержку этого хозяйства, либо "забивается" локальная переменная типа массив с заведомо достаточным размером. Однако его может не хватить при определенных условиях. Пример из собственного опыта: пишем код, который при работе (runtime) должен модифицировать отдельные константы во flash микроконтроллера. В этом случае очевидно нужен буфер на размер страницы flash, чтобы считать ее туда, модифицировать необходимые области и снова скинуть целиком во flash. А теперь представим, что код без перетрансляции (пусть он в библиотеке) должен работать на дериватах микроконтроллера с различным размером страницы flash (например 512 и 2K).

У меня возникла идея (наверняка не оригинальная) размещать буфер динамически не в heap, а в локальном стеке. Для этого я написал следующие функции:
CODE
// ---------------------------------------------------------------------------
//
// The pair __alloc_sp() and __dealloc_sp() implements a runtime allocation
// of memory block within a function. The desired size of the memory buffer
// (in bytes) is given by 'size' parameter of __alloc_sp() that returns
// then a pointer to the allocated buffer.
//
// Afterwards, __dealloc_sp() releases the memory.
//
// The memory is obviously placed in the local stack.
//
// The idea behind is to provide a possibility to use buffers with the sizes
// that may be undefined at compilation time.
//
static __inline __asm
void * __alloc_sp(uint32_t size)
{
; align to 32-bit word
add r0, r0, #3
bic r0, r0, #3

; prepare the return value
sub r0, sp, r0

; save the entry stack pointer for __dealloc_sp()
str sp, [r0, #-4]

; move the stack down to the new position to point
; onto its own saved value!
mov sp, r0
sub sp, sp, #4
bx lr
}

static __inline __asm
long __dealloc_sp(void)
{
pop {r0}
mov sp, r0
bx lr
}

Код под KEIL, возможно под GCC какие-то ключевые слова будут выглядеть иначе.

Пример использования (абстрактный код):
Код
unsigned char flash_the_stuff(void *pvar, int size)
{
    int bufsize = GetMCUFlashPageSize();
    ...
    {
        unsigned char *buffer = __alloc_sp(bufsize);
        ...
        memcpy(buffer, pvar, size);
        ...
        __dealloc_sp();
    }
    return result;
}

Ваше мнение, уважаемые коллеги?

Сообщение отредактировал IgorKossak - Dec 27 2012, 17:48
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
ReAl
сообщение Dec 28 2012, 06:57
Сообщение #2


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Вдогонку.
Не нашёл ничего древнее BC 5.02 разлива 97-го года (в каталоге /media/U2/dosbox_c для запуска в dosbox для такого рода проверок).
Тот же тест, только alloca сидит в malloc.h, а не в персональном файле.
CODE
_foo proc near
;
; void foo(int i, int j)
;
push bp
mov bp,sp
sub sp,2
push si
push di
mov ax,word ptr [bp+4]
;
; {
; if (i > 0) {
;
or ax,ax
jle short @1@6
;
; int *p = alloca(i);
;
mov dx,ax
inc dx
and dx,-2
neg dx
add dx,sp
sub dx,10
cmp dx,sp
jbe short @1@4
xor ax,ax
jmp short @1@5
@1@4:
mov sp,dx
mov ax,dx
@1@5:
mov word ptr [bp-2],ax
;
; moo(p);
;
push ax
call near ptr _moo
add sp,2
@1@6:
;
; }
; if (j > 0) {
;
cmp word ptr [bp+6],0
jle short @1@11
;
; int *p = alloca(2*j);
;
mov dx,word ptr [bp+6]
add dx,dx
inc dx
and dx,-2
neg dx
add dx,sp
sub dx,10
cmp dx,sp
jbe short @1@9
xor ax,ax
jmp short @1@10
@1@9:
mov sp,dx
mov ax,dx
@1@10:
mov word ptr [bp-2],ax
;
; moo(p);
;
push ax
call near ptr _moo
add sp,2
@1@11:
;
; }
; }
;
lea sp,word ptr [bp-6]
pop di
pop si
leave
ret
_foo endp
Всё чисто, просто выделение на стеке на правах временных переменных с такой же очисткой при помощи leave как и для обычных временных переменных.

Кстати, надо было бы alloca(i*sizeof(int)) :-)


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 15:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01385 секунд с 7
ELECTRONIX ©2004-2016