Hallo zusammen,
ich habe folgende Funktion(en) zum lesen eines Strings aus einer RS232
geschrieben:
void AddToRSData(char* Data, char Zeichen, int* CharCount)
{
StrCatChr(Data,Zeichen);
*CharCount=*CharCount+1;
}
unsigned int GetRSData(int UART, char* Data)
{
int CharCount = 0;
int ETXPos = 0;
int Zeichen;
Data[0]='\0';
StartTimerEvent1(1500);
while (!TimeOut1)
{
if (UART==0) Zeichen=uart0_getc(); else
if (UART==1) Zeichen=uart1_getc(); else return 2;
if (Zeichen!=UART_NO_DATA)
{
if (Zeichen==ACK) return ACK; else
if (Zeichen==NAK) return NAK; else
if (Zeichen==EOT) return EOT; else
if (Zeichen==SYN) StartTimerEvent1(1500); else
if (Zeichen==STX) AddToRSData(Data,Zeichen,&CharCount); else
if (Data[0]==STX) AddToRSData(Data,Zeichen,&CharCount);
if (Zeichen==ETX) ETXPos=CharCount-1;
if ((ETXPos>0) & (CharCount-1==ETXPos+2))
{
if (!BuildBCC(Data)) return BCC;
return EOC;
}
}
}
return TOE;
}
Funktioniert bislang alles prima, wenn ich von anderer Stelle ein
char[128] als Data übergebe.
Nun sendet mir eine angeschlossene Maschine eine String mit über 350
Zeichen. Also änderte ich die an Data übergebene Variable einfach auf
char [500]. Jetzt macht das ganze Programm (auch an anderen Stellen) nur
noch Quatsch.
Meine Frage daher: Gibt es Obergrenzen (außer natürlich vorhandenem
Speicher) für Array's?
Komisch finde ich auch, daß GCC mir "Data: 332 bytes (32.4% Full)"
angibt. Da müßten doch eigentlich jetzt mindestens 500 bytes stehen.
(Falls von belang: ATMega162 ist der µC)
Für Erklärungen wäre ich sehr dankbar...
Gruß
Chricky
Chricky schrieb:> Da müßten doch eigentlich jetzt mindestens 500 bytes stehen.
Kommt drauf an wo das Array her kommt, deklariere das mal als globale
Variable.
> Komisch finde ich auch, daß GCC mir "Data: 332 bytes (32.4% Full)"> angibt. Da müßten doch eigentlich jetzt mindestens 500 bytes stehen.
Das Problem ist, dass in dieser Statistik nur der zur Compilezeit
bekannte Speicherverbrauch ist.
Drin nicht enthalten sind zb alle Variablen, die du lokal in einer
Funktion anlegst.
Das ist bei einzelnen Variablen, die nur ein int oder ein char sind
nicht so tragisch. Die paar Bytes hat man fast immer. Aber bei großen
Arrays macht das einen Unterschied, weil sie diese Statistik signifikant
verfälschen. Wenn du also noch andere Funktionen hast, in denen lokale
Arrays mit nicht vernachlässigbarem Speicherverbrauch angelegt werden ->
global machen! Nur dann kann dir diese Statistik eine Aussage liefern,
ob der Speicher knapp wird oder nicht.
Das erste, was du dir unbedingt angewöhnen musst:
Wenn du an eine Funktion ein Array übergibst, dann gehört da IMMER mit
dazu, dass man der Funktion die allokierte Größe des Arrays mitgibt. Die
Funktion kann die nicht selbst bestimmen! Diese Information ist aber
wichtig, damit die Funktion verhindern kann, dass sie über das Array
hinausschreibt und irgendwas anderes im Speicher niederbügelt!
Hallo Karl Heinz Buchegger,
das erlklärt alles! Ich dachte, da schlägt irgendwie die Optimierung zu,
dass der Speicher nicht voller wird...
Da muß ich wohl was nachbessern...
Danke!
Gruß
Chricky
Chricky schrieb:> Data: 332 bytes (32.4% Full)"
Müsste die Deklaration "char Data[500]" nicht im bss segment auftauchen?
Wenn Du schon 322 bytes im Datasegment hast und noch ein bischen den
Stack nützt, läuft evtl. dein SRAM über, sind ja nur 1k. Wars nicht
(früher) so, dass beim avr-gcc erstmal Daten vom Flash ins RAM kopiert
wurden? Habe allerings schon >6 Jahre nichts mehr mit dem avr-gcc
gemacht, kann also sein, dass meine Infos total überholt sind.
Karl Heinz Buchegger schrieb:> Das erste, was du dir unbedingt angewöhnen musst:> Wenn du an eine Funktion ein Array übergibst, dann gehört da IMMER mit> dazu, dass man der Funktion die allokierte Größe des Arrays mitgibt. Die> Funktion kann die nicht selbst bestimmen! Diese Information ist aber> wichtig, damit die Funktion verhindern kann, dass sie über das Array> hinausschreibt und irgendwas anderes im Speicher niederbügelt!
Diese Funktion
ist so gesehen eine Zeitbombe! Denn sie enthält keinen Schutz dagegen,
dass du nicht über Data hinaus irgendwas anderes im Speicher
niederbügelst. (Und dieser Fehler ist wohl der teuerste in der
Geschichte der C-Programmierung. Unzählige Abstürze und Hackerangriffe
gehen auf sein Konto)
Die MUSS so aussehen
Und von da weg arbeitest du dich jetzt rückwärts durch den Code und
fügst die DataSize (welches die allokierte Länge des Arrays darstellt)
bei jedem Aufruf hinzu. Solange, bis du beim tatsächlichen Array
angelegt bist, wo du mit einem sizeof die allokierte Größe feststellen
kannst.
Karl Heinz Buchegger schrieb:> Das erste, was du dir unbedingt angewöhnen musst:>> Wenn du an eine Funktion ein Array übergibst, dann gehört da IMMER mit>> dazu, dass man der Funktion die allokierte Größe des Arrays mitgibt. Die>> Funktion kann die nicht selbst bestimmen! Diese Information ist aber>> wichtig, damit die Funktion verhindern kann, dass sie über das Array>> hinausschreibt und irgendwas anderes im Speicher niederbügelt!
Ja das muß ich wohl lernen. Normal programmiere unter Delphi (also
Pascal). Das Stringverhalten dort ist ja etwas anders...
Danke nochmals...
Gruß
Chricky
Karl Heinz Buchegger schrieb:> void AddToRSData(char* Data, int DataSize, char Zeichen, int* CharCount)> {> if( *CharCount < DataSize - 2 )> {> Data[(*CharCount)++] = Zeichen;> Data[*CharCount+1] = '\0';> }> }
Ich mach ja dann gerne sowas:
void AddToRSData(char* Data, int DataSize, char Zeichen, int* CharCount)
{
if ( *CharCount < DataSize - 2 )
{
Data[(*CharCount)++] = Zeichen;
Data[*CharCount+1] = '\0';
}
else debug(ERROR_OVERFLOW_AddToRSData);
}
D.h. die Funktion geht im Fehlerfall in eine definierte Routine
(Fehlercode wird im LCD angezeigt, Error-LED blinkt, was weiss ich)!
Später kann man durch geeignetes definieren von debug() das alles für
die release Version löschen. Es muss natürlich noch
ERROR_OVERFLOW_AddToRSData passend definiert werden. Am PC kann man
schön mit _LINE__ und __FILE_ arbeiten, aber _FILE_ ist bei uC Apps
zu teuer.
Chricky schrieb:> Gibt es Obergrenzen (außer natürlich vorhandenem> Speicher) für Array's?
Ja, aber weit größer als das, was du bislang benutzt: der größte
Index ist INTMAX. (Beim GCC allerdings limitiert auf INTMAX
Bytes statt Elemente. Hängt möglicherweise damit zusammen,
dass der GCC eine Arithmetik auf Zeigern vom Typ "void *" zulässt
und diese disbezüglich wie "char *" behandelt.)
Karl Heinz Buchegger schrieb:> Wenn du also noch andere Funktionen hast, in denen lokale> Arrays mit nicht vernachlässigbarem Speicherverbrauch angelegt werden ->> global machen!
Es reicht auch, sie in der Funktion zu lassen und einfach static zu
machen.
klausr schrieb:> Chricky schrieb:>> Data: 332 bytes (32.4% Full)">> Müsste die Deklaration "char Data[500]" nicht im bss segment auftauchen?
Nicht wenn sie lokal ist.
> Wars nicht (früher) so, dass beim avr-gcc erstmal Daten vom Flash ins RAM> kopiert wurden?
Das gilt für explizit mit nicht-null initialisierte Variablen.