Forum: Compiler & IDEs Schon wieder sizeof


von Phil (Gast)


Lesenswert?

Hallo Leute!

Ich les jetzt schon ne Weile die Beträge zum Thema sizeof in diesen 
Foren durch, aber irgendwie werde ich daraus nicht schlau.

Ich habe eine Funktion bla, in der ein Array initialisiert wird (größe 
ändert sich), welches dann einer anderen Funktion übergeben wird:

void bla(){
  ....
  uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};
  ...
  machwas(werte);
  ...
}

machwas(uint8_t werte[]){
  uint8_t akt_wert;
  uint8_t anz = sizeof(werte);

  for(akt_wert=0; akt_wert < anz ; akt_wert++){
   ...
  }
  ...
}

Alles was ich will ist, dass die for-Schleife vom ersten bis zum letzten 
Element des Arrays "werte" durchläuft.
Ich hab die gleichen Probleme, wie
Beitrag "Re: Größenangabe von Feldern"
oder
Beitrag "Re: sizeof Frage" ,dass
ich nur "schwachsinnige" Werte wie "0x02" oder "0x01" als Rückgabewert 
erhalte.

Wenn ich in der Funktion "bla" nach der Initialisierung des Arrays
"sizeof(werte)" eingebe, erhalte ich als Rückgabewert die richtige 
Anzahl von Elementen im Array.

Könnt ihr mir weiterhelfen?

Vielen Dank!

Gruß
Phil


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


Lesenswert?

Phil wrote:

> void bla(){
>   ....
>   uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};

Du weißt, dass die Werte zur Laufzeit zugewiesen werden, ja?  Jedesmal
beim Eintritt in die Funktion.

> machwas(uint8_t werte[]){

Das ist äquivalent zu

machwas(uint8_t *werte) {
...

da alle Felder (und Funktionen) in C als Zeiger an aufgerufene
Funktionen übermittelt werden.  Damit sollte dir auch klar sein, warum
sizeof in machwas() eine 2 ergibt.

> Alles was ich will ist, dass die for-Schleife vom ersten bis zum
> letzten Element des Arrays "werte" durchläuft.
1
void machwas(uint8_t *werte, uint8_t count) {
2
  uint8_t i;
3
  for (i = 0; i < count; i++)
4
    ...werte[i]...
5
}
6
7
...
8
  machwas(werte, sizeof werte);

von Roland Praml (Gast)


Lesenswert?

ich vermute (bzw. bin mir eigentlich ziemlich sicher) dass sizeof() 
gleich bei der Compilezeit berechnet wird.

Das einzige was mir dazu einfällt wäre:

machwas (uint8_t *pWerte, unint8_t size) {
 ...
}

und dann der Aufruf:
machwas (werte, sizeof(werte));

von Phil (Gast)


Lesenswert?

"machwas(werte, sizeof werte);"
Das ist ne gute Lösung! ;)

Aber gibt es trotzdem eine Möglichkeit die Größe des Arrays, also die 
Anzahl der Elemente, in der Funktion "machwas" "herauszubekommen"?!?

von Roland Praml (Gast)


Lesenswert?

> Aber gibt es trotzdem eine Möglichkeit die Größe des Arrays, also die
> Anzahl der Elemente, in der Funktion "machwas" "herauszubekommen"?!?

Nein, ausser du reservierst einen Wert als Endezeichen (Bei Strings ist 
das 0x00)

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


Lesenswert?

Phil wrote:

> Aber gibt es trotzdem eine Möglichkeit die Größe des Arrays, also die
> Anzahl der Elemente, in der Funktion "machwas" "herauszubekommen"?!?

Nein.  Bitte denk doch mal nach: diese Funktion bekommt vom dem ganzen
Array nur einen Zeiger auf den Anfang übergeben.  Wie, bitteschön, soll
sie denn dann noch an die Größeninformation herankommen?

von Stefan K. (_sk_)


Lesenswert?

>Aber gibt es trotzdem eine Möglichkeit die Größe des Arrays, also die
>Anzahl der Elemente, in der Funktion "machwas" "herauszubekommen"?!?

Nein.

>machwas(uint8_t werte[]){
werte[] ist ein ptr auf uint8_t. Irgendeine Größenangabe wird da nicht 
übergeben.

Nimm die Lösung von Roland.

Stefan

von Falk (Gast)


Lesenswert?

@Phil

>"machwas(werte, sizeof werte);"
>Das ist ne gute Lösung! ;)

Aber irgendwie glaube ich nciht, dass sie funktionieren wird.

>Aber gibt es trotzdem eine Möglichkeit die Größe des Arrays, also die
>Anzahl der Elemente, in der Funktion "machwas" "herauszubekommen"?!?

Nur wenn die Arrays ein feste Länge haben, welche zur Compilezeit 
bekannt ist.

MFG
Falk

von Phil (Gast)


Lesenswert?

Schlecht.
Im Moment kommt zwar 0x00 nicht als regulärer Wert vor, ich könnte ihn 
also somit als "Flag" nehmen, aber ich muss es für spätere Anwendungen 
"kompatibel" halten. Und da kann es sein, dass es 0x00 als Datenwert 
vorkommt. ;(

Ich belasse es jetzt bei der Lösung. - Hab ich schon vorher mal 
Testweise gehabt, fand ich aber keine schöne Lösung. Wenn's aber nicht 
geht ....

Danke!

Gruß
Phil

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


Lesenswert?

Falk wrote:

> Nur wenn die Arrays ein feste Länge haben, welche zur Compilezeit
> bekannt ist.

Die Größe eines Arrays ist dem Compiler immer zur Compilezeit
bekannt, sonst wäre es keins.  Entweder hat sie der Programmierer
explizit festgelegt oder aber implizit, indem er [] schreibt und
die Gesamtgröße aus der Anzahl der Initialisierungselemente
genommen wird.

Etwas anderes ist es, wenn man malloc() benutzt, aber dann hat man
kein Array, sondern einen Zeiger.

von Falk (Gast)


Lesenswert?

@Jörg Wunsch

>Die Größe eines Arrays ist dem Compiler immer zur Compilezeit
>bekannt, sonst wäre es keins.  Entweder hat sie der Programmierer

Ähhhh, ja. ;-)

>Etwas anderes ist es, wenn man malloc() benutzt, aber dann hat man
>kein Array, sondern einen Zeiger.

Das ist doch aber eben das Problem des OP, oder?

MFG
Falk

von Stefan K. (_sk_)


Lesenswert?

>Schlecht.
>Im Moment kommt zwar 0x00 nicht als regulärer Wert vor, ich könnte ihn
>also somit als "Flag" nehmen, aber ich muss es für spätere Anwendungen
>"kompatibel" halten. Und da kann es sein, dass es 0x00 als Datenwert
>vorkommt. ;(

Was ist genau "schlecht"?

Ich denke, Du vermischst Strings und Arrays. Wenn Du Deine Funktion so 
aufbaust, wie Roland vorgeschlagen hat, hast Du keine Probleme mit der 
"0" (solange Du nicht irgendwelche String-Funktionen auf Dein Array 
loslässt):
1
machwas (uint8_t *pWerte, unint8_t size) {
2
 ...
3
}
Du kannst also auch Nullen in Dein Array füllen, die Größe, die Du mit 
sizeof bestimmt hast, wird dadurch nicht tangiert.

Gruß, Stefan

von Phil (Gast)


Lesenswert?

Ok, jetzt versteh ich, was  Jörg Wunsch mit "Du weißt, dass die Werte 
zur Laufzeit zugewiesen werden, ja?  Jedesmal beim Eintritt in die 
Funktion." gemeint hat.

Wie gesagt, die größe ist dynamisch.
1
void bla(){
2
  ....
3
  uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};
4
  ...
5
  machwas(werte);
6
  ...
7
  werte[] = {0xFF, 0xC2, 0x1F, 0x88}; //geht nicht
8
  ...
9
  machwas(werte);
10
  ...
11
}

AVR will, dass ich die zweite Zuweisung so
1
werte[0] = 0xFF;
2
werte[1] = 0xC2;
3
werte[2] = 0x1F;
4
werte[3] = 0x88;
mache.

Das muss doch irgendwie auch anders gehen, oder?

Verzeiht, bin ein kleiner Newbie!

Danke schonmal!

Gruß
Phil

von Karl H. (kbuchegg)


Lesenswert?

Falk wrote:
> @Phil
>
>>"machwas(werte, sizeof werte);"
>>Das ist ne gute Lösung! ;)
>
> Aber irgendwie glaube ich nciht, dass sie funktionieren wird.

In diesem speziellen Fall schon, da es sich um ein
uint8_t Array handelt.

Ansonsten macht man den Ansatz:

#define ELEMENTS(x)  (sizeof(x)/sizeof(*x))

und benutzt

     machwas( werte, ELEMENTS(werte) );

Man dividiert also die kokmplette Byte-Größe des
Arrays durch die Byte-Größe des ersten Elements
und erhält so die Anzahl der Elemente in diesem
Array.

Disclaimer: Das geht natürlich wieder nur, wenn ein
Array auch als Array sichtbar ist. In dem Moment, indem
ein Array zu einem Pointer degeneriert ist, klappt das
klarerweise nicht mehr.

Drum bin ich eigentlich auch ein Gegner der Schreibweise

void foo( int myArray[] )
{
}

denn das suggeriert etwas, das nicht stimmt: Da wird kein
Array übergeben, sondern die Adresse des ersten Elements.

von Karl H. (kbuchegg)


Lesenswert?

Phil wrote:
> Ok, jetzt versteh ich, was  Jörg Wunsch mit "Du weißt, dass die Werte
> zur Laufzeit zugewiesen werden, ja?  Jedesmal beim Eintritt in die
> Funktion." gemeint hat.
>
> Wie gesagt, die größe ist dynamisch.
>
1
void bla(){
2
>   ....
3
>   uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};
4
>   ...
5
>   machwas(werte);
6
>   ...
7
>   werte[] = {0xFF, 0xC2, 0x1F, 0x88}; //geht nicht
8
>   ...
9
>   machwas(werte);
10
>   ...
11
> }
>
> AVR will, dass ich die zweite Zuweisung so
>
1
werte[0] = 0xFF;
2
> werte[1] = 0xC2;
3
> werte[2] = 0x1F;
4
> werte[3] = 0x88;
5
>
> mache.
>
> Das muss doch irgendwie auch anders gehen, oder?

Nein.
Das geht nicht anders.

Das erste
1
  uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};

ist keine Zuweisung, sondern einen Initialisierung.
Bei einer Initialisierung gelten andere Regeln.

Das hier
1
  werte = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};

wäre eine Zuweisung, so sie denn syntaktisch korrekt
wäre. Nur: In C kann man Arrays nicht zuweisen. Man
kann sie als ganzes initialisieren, aber man kann mit
einem Array als Ganzes praktisch nichts machen. Zb.
kann man einem Array nicht ein anderes Array zuweisen
und man kann daher auch ein Array nicht an eine Funktion
übergeben, denn dazu wäre ja die Zuweisung des
übergebenen Arrays an ein lokales Array innerhalb der
Funktion notwendig und das geht nicht (Array-Zuweisung).

von Phil (Gast)


Lesenswert?

Und wie dann?
Soll ich etwa jedesmal eine neue Variable als array anlegen?!?

Da kommt man ja irgendwann vor lauter Variablennamen völlig 
durcheinander! ;(

Gruß
Phil

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


Lesenswert?

Du kannst sie in getrennten Blöcken anlegen:
1
void bla(){
2
  ....
3
  {
4
    uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};
5
    ...
6
    machwas(werte);
7
  }
8
  ...
9
  {
10
    uint8_t werte[] = {0xFF, 0xC2, 0x1F, 0x88};
11
    ...
12
    machwas(werte);
13
  }
14
  ...
15
}

Damit endet der Gültigkeitsbereich ("scope") eines jeden Arrays namens
"werte" an der schließenden geschweiften Klammer.

von Phil (Gast)


Lesenswert?

Funtkioniert! - Danke!

Gruß
Phil

von Falk (Gast)


Lesenswert?

@Jörg Wunsch

>Du kannst sie in getrennten Blöcken anlegen:
>void bla(){
>  ....
>  {
>    uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};
>    ...
>    machwas(werte);
>  }
>  ...
>  {
>    uint8_t werte[] = {0xFF, 0xC2, 0x1F, 0x88};
>    ...
>    machwas(werte);
>  }
>  ...
>}

Werden dadurch nicht zwei Arrays angelegt? Speicherverbrauch?

MfG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Falk wrote:
> @Jörg Wunsch
>
>>Du kannst sie in getrennten Blöcken anlegen:
>>void bla(){
>>  ....
>>  {
>>    uint8_t werte[] = {0x12, 0x33, 0xA9, 0x11, 0xC8, 0xE4};
>>    ...
>>    machwas(werte);
>>  }
>>  ...
>>  {
>>    uint8_t werte[] = {0xFF, 0xC2, 0x1F, 0x88};
>>    ...
>>    machwas(werte);
>>  }
>>  ...
>>}
>
> Werden dadurch nicht zwei Arrays angelegt? Speicherverbrauch?
>

rein formal gesehen: ja.
Allerdings wird das erste Array zerstört, bevor das zweite
angelegt wird. Solange die Arrays gleich groß sind, stehen
die Chancen nicht schlecht, das beide Arrays im gleichen
Speicher erzeugt werden.

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


Lesenswert?

Ich würde allerdings für das Ganze wohl eher pgmspace-arrays
bevorzugen.  Den Platz für die Initialisierungswerte braucht man
so und so im ROM (auf die eine oder andere Weise), und auf den
LPM- statt LDS-Zugriff kommt's sicher nicht an.

von Karl H. (kbuchegg)


Lesenswert?

Seh ich auch so.

2 konstante globale Arrays ins Flash und falls die Funktionen
umschreiben zu aufwändig ist, bzw. die Werte zwischendurch
mal temporär geändert werden müssen, mittels memcpy_p ins
RAM holen.

(Dürfte aber für den OP noch zu schwierig sein :-)

von Phil (Gast)


Lesenswert?

Scheint mir auch so! ;) Überleg z.B. noch immer, für was "OP" stehen 
soll.
Ich kann mir vorstellen, in welche Richtung es geht (=> 
DAU/Newbie/Greenhorn) aber die richtigen Wörter hab ich noch nicht 
gefunden. :D

Aber ich bin willig es zu lernen!

Gruß
Phil

von Karl H. (kbuchegg)


Lesenswert?

Phil wrote:
> Scheint mir auch so! ;) Überleg z.B. noch immer, für was "OP" stehen
> soll.

Sorry. Da kommt meine Vergangenheit in internationalen Foren durch.
OP steht für 'original Poster', also derjenige, der den Thread
eröffnet hat.

> Ich kann mir vorstellen, in welche Richtung es geht (=>
> DAU/Newbie/Greenhorn) aber die richtigen Wörter hab ich noch nicht
> gefunden. :D
>
> Aber ich bin willig es zu lernen!

Dann guckst du hier

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29

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.