|
Динамическое размещение буфера в функции, Если размер изначально неизвестен... |
|
|
|
Dec 27 2012, 10:40
|
Знающий
   
Группа: Участник
Сообщений: 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] - для короткого!!!
|
|
|
|
|
 |
Ответов
|
Dec 27 2012, 12:36
|
Гуру
     
Группа: Свой
Сообщений: 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++]); }
} Не подходит?
|
|
|
|
|
Dec 27 2012, 13:11
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
|
Dec 27 2012, 14:10
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
Сообщений в этой теме
KnightIgor Динамическое размещение буфера в функции Dec 27 2012, 10:40 scifi Нельзя самовольно двигать указатель стека, им расп... Dec 27 2012, 11:45 VAI Здесь посмотрите http://electronix.ru/forum/index.... Dec 27 2012, 11:54 SSerge А вот __aeabi_memclr4 вызывать было совершенно не ... Dec 27 2012, 15:28 ReAl Тю. GCC стек двигает. Причём и для старого C89 вар... Dec 27 2012, 16:11 _Pasha alloca() и еще связным списком попахивает Так что... Dec 27 2012, 17:08 ReAl Цитата(_Pasha @ Dec 27 2012, 19:08) alloc... Dec 27 2012, 19:36 ReAl Вдогонку.
Не нашёл ничего древнее BC 5.02 разлива ... Dec 28 2012, 06:57
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|