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.
Hallo Läubi, das ändert den Speicherverbrauch, das Programm macht jedoch noch mehr Quatsch...!?
> 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
1 | void AddToRSData(char* Data, char Zeichen, int* CharCount) |
2 | {
|
3 | StrCatChr(Data,Zeichen); |
4 | *CharCount=*CharCount+1; |
5 | }
|
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
1 | void AddToRSData(char* Data, int DataSize, char Zeichen, int* CharCount) |
2 | {
|
3 | if( *CharCount < DataSize - 2 ) |
4 | {
|
5 | Data[(*CharCount)++] = Zeichen; |
6 | Data[*CharCount+1] = '\0'; |
7 | }
|
8 | }
|
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.
1 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
2 | |
3 | ....
|
4 | |
5 | char String[400]; |
6 | |
7 | |
8 | ....
|
9 | |
10 | GetRSData( 0, String, ARRAY_SIZE(String) ); |
11 | ...
|
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.
Gemeint sind diese Präprozessor Macros: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.