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

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


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(KnightIgor @ Dec 27 2012, 12:40) *
Привет всем.

Бывает, что на этапе компиляции размер требуемого буфера внутри функции точно неизвестен. В этом случае используют либо динамическое размещение памяти (malloc), что тянет за собой всю поддержку этого хозяйства, либо "забивается" локальная переменная типа массив с заведомо достаточным размером.

Был ещё в Си такой вариант:
Код
void SendData(unsigned int data_length)
{
    unsigned char buffer[data_length];
    unsigned char i=0;
    while (i<data_length) {
        USART_PutChar(&GSM_UART, buffer[i++]);
    }

}


Не подходит?
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 27 2012, 13:11
Сообщение #3


Знающий
****

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



Цитата(_Артём_ @ Dec 27 2012, 13:36) *
Был ещё в Си такой вариант:
Код
void SendData(unsigned int data_length)
{
    unsigned char buffer[data_length];
}

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

Цитата(VAI @ Dec 27 2012, 12:54) *

Посмотрел. Попробовал: как и ожидалось (написал в сообщении #5 здесь), компилятор ругается, желая видеть константы в размерности массива.
Я что, один под KEIL пишу?

Цитата(scifi @ Dec 27 2012, 12:45) *
Нельзя самовольно двигать указатель стека, им распоряжается компилятор. Если сдвинуть указатель стека, то потеряются локальные переменные, выделенные в стеке.

Я тоже так предполагал. Но в кодах, что я видел, нет адресаций с базой SP; как правило, на входе указатель на область локальных переменных грузится в какой-либо общий регистр, и уже через него идет обращение.

P.S. "Извините, был напуган" (из анекдота): таки да, есть код относительно SP. То есть, мною предложенный код будет работать (и работает) лишь в ограниченных условиях.

Сообщение отредактировал KnightIgor - Dec 27 2012, 13:35
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Dec 27 2012, 13:57
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(KnightIgor @ Dec 27 2012, 15:11) *
Компилятор будет ругаться, что data_length должна быть константой. Во всяком случае KEIL.

Что у кейла нет поддержки С99?
Если есть, то должен откомпилировать.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 27 2012, 14:10
Сообщение #5


Знающий
****

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



Цитата(_Артём_ @ Dec 27 2012, 14:57) *
Что у кейла нет поддержки С99?

Поддержка действительно есть (ключ --c99). Пример компилируется. Реализация такого "безразмерного" массива осуществляется через malloc/free:
Код
                          AREA ||i.foo||, CODE, READONLY, ALIGN=1

                  ||foo|| PROC
;;;845    
;;;846    int foo(int x)
000000  e92d41f0          PUSH     {r4-r8,lr}
;;;847    {
000004  4604              MOV      r4,r0
;;;848        int b[x];
000006  4626              MOV      r6,r4
000008  00b0              LSLS     r0,r6,#2
00000a  f7fffffe          BL       malloc
00000e  4605              MOV      r5,r0
;;;849        memset(b, 0, sizeof(b));
000010  00b1              LSLS     r1,r6,#2
000012  4628              MOV      r0,r5
000014  f7fffffe          BL       __aeabi_memclr4
;;;850        return b[0];
000018  4628              MOV      r0,r5
00001a  682f              LDR      r7,[r5,#0]
00001c  f7fffffe          BL       free
000020  4638              MOV      r0,r7
;;;851    }
000022  e8bd81f0          POP      {r4-r8,pc}
;;;852    // -----------------------------------------------------------------------------
                          ENDP
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Dec 27 2012, 14:34
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(KnightIgor @ Dec 27 2012, 16:10) *
Поддержка действительно есть (ключ --c99). Пример компилируется. Реализация такого "безразмерного" массива осуществляется через malloc/free:

Точно. Нет бы им SP сдвинуть...
Go to the top of the page
 
+Quote Post



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

 


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


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