malloc() und calloc() haben einen recht großen Overhead, was RAM und Flash-Verbrauch angeht. Immerhin muss eine Liste der allokierten Blöcke verwaltet werden, und das frisst RAM. Ausserdem führen aufeinander folgende malloc/free Zyklen zu einer Speicherfragmentierung, so daß evtl kein passender Block mehr verfügbar ist.
Seltsamerweise kennt avr-gcc kein alloca(), aber so geht's:
Code:
#include <stdlib.h>
void foo (unsigned short nbytes)
{
unsigned short i;
unsigned char *buf;
buf = (unsigned char*) __builtin_alloca ((size_t) nbytes);
for (i=0; i < nbytes; i++)
buf[i] = 0;
}
Synopsis:
void* __builtin_alloca (size_t nbytes);
__builtin_alloca() ist keine libc-Funktion wie malloc() und calloc(), sondern ein Builtin von GCC.
Der Speicherplatz wird auf dem Stapel angelegt, indem einfach der Stackpointer entsprechend angepasst wird:
Code:
.text
.global foo
.type foo, @function
foo:
/* prologue: frame size=0 */
push r28
push r29
in r28,__SP_L__
in r29,__SP_H__
/* prologue end (size=4) */
in r20,__SP_L__ ; tmp47 ; 41 *movhi/7 [length = 2]
in r21,__SP_H__ ; tmp47
in r18,__SP_L__ ; ; 76 *movhi/7 [length = 2]
in r19,__SP_H__ ;
sub r18,r24 ; , nbytes ; 11 subhi3/1 [length = 2]
sbc r19,r25 ; , nbytes
in __tmp_reg__,__SREG__ ; 77 *movhi/6 [length = 5]
cli
out __SP_H__,r19 ;
out __SREG__,__tmp_reg__
out __SP_L__,r18 ;
subi r18,lo8(-(1)) ; buf, ; 12 *addhi3/4 [length = 2]
sbci r19,hi8(-(1)) ; buf,
sbiw r24,0 ; nbytes ; 52 tsthi/1 [length = 1]
breq .L7 ; , ; 53 branch [length = 1]
movw r30,r18 ; buf, buf ; 68 *movhi/1 [length = 1]
.L5:
st Z+,__zero_reg__ ; , ; 25 *movqi/3 [length = 1]
sbiw r24,1 ; i, ; 70 *addhi3/3 [length = 1]
brne .L5 ; , ; 72 branch [length = 1]
.L7:
in __tmp_reg__,__SREG__ ; 44 *movhi/6 [length = 5]
cli
out __SP_H__,r21 ; tmp47
out __SREG__,__tmp_reg__
out __SP_L__,r20 ; tmp47
/* epilogue: frame size=0 */
pop r29
pop r28
ret
Vom Overhead ist so was optimal, allerdings ist das Bereich nicht vorinitialisiert und muss auch nicht freigegeben werden, das geschieht am Ende des C-Blocks automatisch. Der Bereich ist daher nur innerhalb des Blocks gültig, der ihn beschafft hat. Mit return einen Zeiger auf den Bereich rausliefern ist also nicht.
...und ein Laufzeit-Check ob der Platz noch ausreicht scheints auch nicht zu geben, evtl kann man das selber erledigen.
Mit gcc-Option -fstack-check wird anderer Code generiert, vielleicht tut's die ja schon...?
::Edit::
...und ANSI-C ist alloca() auch nicht, sondern GNU-C.
avr-gcc -ansi ...
wird das also anmeckern, sollte zumindest.
Lesezeichen