Forum: Compiler & IDEs Array Obergrenzen?


von Chricky (Gast)


Lesenswert?

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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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.

von Chricky (Gast)


Lesenswert?

Hallo Läubi,

das ändert den Speicherverbrauch, das Programm macht jedoch noch mehr 
Quatsch...!?

von Chricky (Gast)


Lesenswert?

...und der µC hängt sich sogar weg...

von Karl H. (kbuchegg)


Lesenswert?

Tja.
Kein Mensch sagt, dass das das einzige Problem im Code ist

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Karl H. (kbuchegg)


Lesenswert?

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!

von Chricky (Gast)


Lesenswert?

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

von klausr (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
...

von Chricky (Gast)


Lesenswert?

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

von klausr (Gast)


Lesenswert?

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.

von klausr (Gast)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.)

von Rolf Magnus (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.