Kann es sein, dass Array A und B nicht gleich viel Speicher belegen?
Oder legt der Compiler die Daten automatisch hintereinander?
Gibt es einen Unterschied, was den Speicherbedarf anbelangt, zwischen
ArrayA und ArrayC?
Architektur: ARM Cortex M3
Compiler: ARM-GCC
Danke!
Holger K. schrieb:> Kann es sein, dass Array A und B nicht gleich viel Speicher belegen?
Ja natürlich; so wie Du es angefordert hast!
> Oder legt der Compiler die Daten automatisch hintereinander?
Letzlich entscheidet der Linker, wo Deine Variablen angelegt werden:
RAM, ROM, batteriegepufferter Bereich, ...
m.n. schrieb:> Ja natürlich; so wie Du es angefordert hast!
Ich habe im Beispiel 4x8Bit angefordert = 32Bit und 1x32Bit = 32Bit
Im Code selbst habe ich sicher in beiden Fällen genau 32Bit zur
Verfügung.
Die Frage ist, wie es im Speicher des Controllers aussieht.
Liegen dort die ersten 4 bytes hintereinander:
|byte1|byte2|byte3|byte4| = 32bit
| 32Bit | = 32bit
Oder sieht es in etwa so aus im Flash:
|byte1| masked 24Bit |byte2 masked 24Bit|....
Holger K. schrieb:> Liegen dort die ersten 4 bytes hintereinander:
Ja, auf jeden Fall. Anders wäre das Feld Speicherverschwendung und die
Indizierung bzw. Zugriff über Zeiger wäre ein Problem.
Würdest Du schreiben:
const uint32_t ArrayB[4];
dann werden 16 Bytes belegt.
Am besten sieht man immer ins Listing vom Compiler und die .map-Datei
des Linkers. Da steht es dann ganz genau.
Bei Arrays müssen die Elemente direkt hintereinander liegen, damit das
mit der Indizierung klappt, wo es anders aussehen kann ist bei Structs,
wenn der Compiler Padding einfügt um beispielsweise 16 bit Variablen an
einer durch 2 und 32 bit Variablen an einer durch 4 teilbaren Adresse
abzulegen.
@ m.n. (Gast)
>> Liegen dort die ersten 4 bytes hintereinander:>Ja, auf jeden Fall. Anders wäre das Feld Speicherverschwendung und die>Indizierung bzw. Zugriff über Zeiger wäre ein Problem.
Nö, der Compiler kann das auch mit Leerbytes immer auf /4 teilbaren (32
Bit) Adressen ausrichten,. Stichwort Padding Bytes. Oder gilt das nur
für Structs?
Falk B. schrieb:> Nö,Falk B. schrieb:> Oder gilt das nur für Structs?
Erst einmal NEIN sagen, um dann zu fragen, wie es tatsächlich ist.
Komischer Vogel!
du kannst dir die Byteorder z.B auf einem lcd anzeigen lassen:
u32 owx_rx_buffer[1]={0x11223344};
u8 *owx_rx8=(owx_rx_buffer);
lcd_int(owx_rx8[0]);
lcd_int(owx_rx8[1]);
lcd_int(owx_rx8[2]);
lcd_int(owx_rx8[3]);
m.n. schrieb:> Holger K. schrieb:>> Liegen dort die ersten 4 bytes hintereinander:>> Ja, auf jeden Fall.
Richtig.
> Anders wäre das Feld Speicherverschwendung und die> Indizierung bzw. Zugriff über Zeiger wäre ein Problem.
Falsch. Das ist nicht der Grund. Selbstverständlich könnte ein
C-Compiler Padding hinzufügen und das beim Zugriff über den Index und
bei Pointerarithmetik entsprechend berücksichtigen. Und es gäbe auch
Gründe daß zu tun (Kosten für unalignedten Speicherzugriff).
Der wahre Grund, warum jeder C-Compiler Arrays dicht gepackt im
Speicher ablegt, ist daß das von C-Standard so gefordert wird.
Bei structs läßt der Standard den Compilerbauern mehr Freiheit, da
dürfen sie nach Belieben Padding einfügen.
Das war auch mein Kenntnisstand.
Arrays werden eventuell so ausgerichtet, dass sie an günstigen
Positionen im Ram stehen (z.B. 32Bit raster). Ihre Daten werden jedoch
lückenlos aneinander gereiht (im Byte-Raster).
Und ja, das ist für die Performance nicht immer optimal. Intel
Prozessoren können damit jedoch sehr gut umgehen.
Falk B. schrieb:> Nö, der Compiler kann das auch
Nein, er kann nicht machen was er will, er muss sich an das Platform-ABI
halten, dort ist das alles penbibelst genau definiert, bis aufs letzte
Bit genau.
Axel S. schrieb:>> Anders wäre das Feld Speicherverschwendung und die>> Indizierung bzw. Zugriff über Zeiger wäre ein Problem.>> Falsch. Das ist nicht der Grund. Selbstverständlich könnte ein> C-Compiler Padding hinzufügen und das beim Zugriff über den Index und> bei Pointerarithmetik entsprechend berücksichtigen.
Falsch?
Es wäre in jedem Fall Speicherverschwendung! Was ein Compiler alles
könnte ist hier nicht gefragt. Bei einem Zeigerzugriff muß dem Compiler
die Adresse des Zeigers garnicht bekannt sein, und wenn der Zugriff über
z.B. uint8_t *p sein Ziel nicht verfehlen soll, müssen die Bytes direkt
hintereinander liegen, egal ob im RAM, ROM, IO-Bereich oder extern.
Axel S. schrieb:> Und es gäbe auch> Gründe daß zu tun (Kosten für unalignedten Speicherzugriff).
Bei Bytes überhaupt kein Problem und das Alignment wird schon im
Buscontroller erledigt wie auch die Ausrichtung (endianness) ;-)
Vielen Dank für eure ausführliche Antwort.
Der Hintergrund meiner Frage war, zu prüfen, ob es sinnvoller wäre, mein
Array mit uint32_t zu definieren, um evtl. Speicher zu sparen.
Berechnungen werden mit den Daten keine durchgeführt.
Es sind lediglich PixelInformationen abgespeichert.
Nach dem durchlesen der Antworten komme ich zum Schluss, dass es kein
Nachteil ist, das array als uint8_t zu definieren.
@ Bernd K. (prof7bit)
>> Nö, der Compiler kann das auch>Nein, er kann nicht machen was er will, er muss sich an das Platform-ABI>halten,
Das hat doch keiner bezweifelt.
Kleines Rätsel für die Compilerkenner.
1
int8_tmyarray[4];
2
3
inta=sizeof(myarray);
Auf welchem Prozesor kommt für a == 4 raus, und es werden trotzdem
4x16Bit Speicher belegt? ;-)
Ich vermute, dass ein 32bit Prozessor 32bit Variablen schneller (oder
zumindest gleich schnell) verarbeiten kann, als 8bit.
Wenn du viele Pixel Speicherst, würde ich daher 32bit breite Variablen
benutzen. Kann nicht schaden.
Oder brauchst sie aus irgend einem Grund in kleineren Päckchen?
Das wird ein Prozessor mit einem Adressraum im 16Bit Raster sein. Also
einer, der gar nicht einzelne Bytes adressieren kann.
Denn es muss ja immer noch die Regel gelten, dass myarray+1 auf den
zweiten Wert im Array zeigt.
Vielleicht der PDP-11 ?
@ Christopher B. (chrimbo) Benutzerseite
>> Auf welchem Prozesor kommt für a == 4 raus, und es werden trotzdem>> 4x16Bit Speicher belegt? ;-)>Ich vermute auf irgendeinem DSP?
Wärmer . . .
Kleiner Tip. Der Prozessor ist auch hier im Wiki zu finden . . .
@ Stefan Us (stefanus)
>Das wird ein Prozessor mit einem Adressraum im 16Bit Raster sein. Also>einer, der gar nicht einzelne Bytes adressieren kann.
Stimmt.
>Denn es muss ja immer noch die Regel gelten, dass myarray+1 auf den>zweiten Wert im Array zeigt.
Das war doch nie in Frage gestellt.
>Vielleicht der PDP-11 ?
Nein, ist schon was relativ Modernes.
m.n. schrieb:> Axel S. schrieb:>>> Anders wäre das Feld Speicherverschwendung und die>>> Indizierung bzw. Zugriff über Zeiger wäre ein Problem.>>>> Falsch. Das ist nicht der Grund. Selbstverständlich könnte ein>> C-Compiler Padding hinzufügen und das beim Zugriff über den Index und>> bei Pointerarithmetik entsprechend berücksichtigen.>> Falsch?> Es wäre in jedem Fall Speicherverschwendung!
Offensichtlich war das für die Leute die den C-Standard geschrieben
haben kein Argument. Sonst wären auch structs defaultmäßig gepackt.
> Was ein Compiler alles könnte ist hier nicht gefragt.
Da du die Behauptung aufgestellt hast, das würde nicht gehen, ist das
sehr wohl ein gültiges Gegenargument.
> Bei einem Zeigerzugriff muß dem Compiler> die Adresse des Zeigers garnicht bekannt sein, und wenn der Zugriff über> z.B. uint8_t *p sein Ziel nicht verfehlen soll, müssen die Bytes direkt> hintereinander liegen, egal ob im RAM, ROM, IO-Bereich oder extern.
Keineswegs. Ein Compiler könnte durchaus alle Zeiger so implementieren,
daß sie nur auf Wortgrenzen zu 32 Bit zeigen können. Wenn wir annehmen,
daß die Plattform den Speicher in Bytes zu 8 Bit ansprechen kann und
wenn wir weiter annehmen, daß ein Pointer eine nackte Adresse ist, dann
wären in diesem Fall die untersten zwei Bits jedes Pointers immer Null.
Und ein Inkrement würde den "nackten" Wert um 4 (respekive Vielfache von
4 für Arrays von längeren Datentypen) erhöhen.
Genauso gut könnte ein solcher Compiler aber auch die untersten zwei
Bits gar nicht in der Pointervariable speichern (die sind ja ohnehin 0),
sondern nur die höherwertigen Bits. Für die Umwandlung eines Pointers in
eine Speicheradresse müßte man den Wert dann halt zweimal nach links
schieben. Im Gegenzug könnte man die beiden freiwerdenden höchsten Bits
benutzen, um generalisierte Pointer für Harvard-Architekturen mit
mehreren Adreßräumen zu implementieren.
Deine Behauptung "man muß Arrays dicht speichern, weil sonst Indizierung
und Pointer nicht funktionieren" ist also - falsch
Axel S. schrieb:> Deine Behauptung "man muß Arrays dicht speichern, weil sonst Indizierung> und Pointer nicht funktionieren"
Das habe ich garnicht geschrieben. Ich schrieb von "wäre ein Problem",
was nicht unlösbar wäre aber völlig unnötig.
Axel S. schrieb:> Ein Compiler könnte durchausAxel S. schrieb:> Genauso gut könnte ein solcher CompilerAxel S. schrieb:> Im Gegenzug könnte manAxel S. schrieb:> wenn wir weiter annehmen,
Den Compiler, den Du hier konstruierst, würde keiner haben wollen. Zudem
müßte sich jemand die Mühe machen, für diesen Compiler noch eine CPU zu
bauen. Ganz schön viel Konjunktiv!
Ich habe das ganze nun im MemoryBrowser des STM angeschaut.
Die Initialisierten Bytes des uint8_t arrays liegen direkt
hintereinander, ohne padding bits.
Danke
Axel S. schrieb:> Genauso gut könnte ein solcher Compiler aber auch die untersten zwei> Bits gar nicht in der Pointervariable speichern (die sind ja ohnehin 0),> sondern nur die höherwertigen Bits. Für die Umwandlung eines Pointers in> eine Speicheradresse müßte man den Wert dann halt zweimal nach links> schieben. Im Gegenzug könnte man die beiden freiwerdenden höchsten Bits> benutzen, um generalisierte Pointer für Harvard-Architekturen mit> mehreren Adreßräumen zu implementieren.
Das wäre dann entweder kein "C" Compiler oder Dein "char" Typ wäre netto
32 Bit breit. Beides klingt IMHO nicht grade clever.
Übrigens macht ARM Cortex-M das mit den generalisierten Pointern, weil
32 Bits für µCs genug Addressraum bereit stellen.
@ Jim Meba (turboj)
>Das wäre dann entweder kein "C" Compiler oder Dein "char" Typ wäre netto>32 Bit breit. Beides klingt IMHO nicht grade clever.
Sag das mal TI! Siehe Anhang (und damit die Auflösung des Rätsels).
Falk B. schrieb:> Nein, ist schon was relativ Modernes.
Aus Wikipedia:
"Texas Instruments TMS320 is a blanket name for a series of digital
signal processors (DSPs) from Texas Instruments. It was introduced on
April 8, 1983 through the TMS32010 processor, which was then the fastest
DSP on the market."
Von 1983 die alte Gurke.