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

 
 
> Динамическое размещение буфера в функции, Если размер изначально неизвестен...
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
Ответов
_Pasha
сообщение Dec 27 2012, 17:08
Сообщение #2


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



alloca() и еще связным списком попахивает sm.gif Так что лучше с размером-сразу.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Dec 27 2012, 19:36
Сообщение #3


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

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



Цитата(_Pasha @ Dec 27 2012, 19:08) *
alloca() и еще связным списком попахивает sm.gif Так что лучше с размером-сразу.
Я же написал -- в GCC для примера выше код с alloca и с C99-массивом переменного размера одинаков. alloca был придуман именно для того, чтобы для "динамической" памяти, которая освобождается в той же функции, в которой выделялась, уйти от списков и фрагментации. Ценой необходимости запаса не стеке. В некотором смысле C99-массивы переменной длины — это синтаксический сахар над alloca. Ну или alloca -- предшественник этих массивов.
Цитата
NAME
alloca - allocate memory that is automatically freed

SYNOPSIS
#include <alloca.h>

void *alloca(size_t size);

DESCRIPTION
The alloca() function allocates size bytes of space in the stack frame
of the caller. This temporary space is automatically freed when the
function that called alloca() returns to its caller.
Никакие списки тут не нужны.
Код
#include <alloca.h>

void moo(int *p);

void foo(int i, int j)
{
        if (i > 0) {
                int *p = alloca(i);
                moo(p);
        }
        if (j > 0) {
                int *p = alloca(2*j);
                moo(p);
        }
}

Код
foo:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 1, uses_anonymous_args = 0
    push    {r3, r4, r7, lr}
    cmp    r0, #0
    add    r7, sp, #0
    mov    r4, r1
    ble    .L2
    adds    r0, r0, #14
    bic    r0, r0, #7
    sub    sp, sp, r0; выделили первый запрос
    mov    r0, sp
    bl    moo
.L2:
    cmp    r4, #0
    ble    .L1
    lsls    r4, r4, #1
    adds    r4, r4, #14
    bic    r4, r4, #7
    sub    sp, sp, r4; выделили второй запрос
    mov    r0, sp
    bl    moo
.L1:
    mov    sp, r7; освобождаем одним махом всё (если вообще выделяли)
    pop    {r3, r4, r7, pc}


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



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

 


RSS Текстовая версия Сейчас: 5th September 2025 - 00:12
Рейтинг@Mail.ru


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