Forum: Mikrocontroller und Digitale Elektronik 8Bit Variablen auf einem 32Bit Mikrocontroller


von Holger K. (holgerkraehe)


Lesenswert?

Hallo zusammen

Folgende Thematik:
1
const uint8_t  ArrayA[4];
2
const uint32_t ArrayB[1];
3
4
uint8_t  ArrayC[4];
5
uint32_t ArrayD[1];

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!

von asd (Gast)


Lesenswert?

Probier's aus: "sizeof" existiert.

von m.n. (Gast)


Lesenswert?

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

von Holger K. (holgerkraehe)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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.

von Rüdiger (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@  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?

von m.n. (Gast)


Lesenswert?

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!

von Stefan K. (stefan64)


Lesenswert?

Beim Cortex M3 werden beide Arrays gleich groß:
1
    volatile uint8_t testArray[4] = {1, 2, 3, 4};
2
    volatile int mysize = sizeof(testArray);
3
    // mysize bekommt den Wert 4 (gcc, STM32F407)

Allgemein kann man das aber nicht sagen, es gibt auch 32-Bit 
Processoren, die nur 32 Bit Datenworte adressieren können.

Gruß, Stefan

von grundschüler (Gast)


Lesenswert?

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]);

von Axel S. (a-za-z0-9)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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

von Holger K. (holgerkraehe)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@  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_t myarray[4];
2
3
int a = sizeof(myarray);

Auf welchem Prozesor kommt für a == 4 raus, und es werden trotzdem 
4x16Bit Speicher belegt? ;-)

von Stefan F. (Gast)


Lesenswert?

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?

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Kleines Rätsel für die Compilerkenner.
>
>
1
> int8_t myarray[4];
2
> 
3
> int a = sizeof(myarray);
4
>
>
> Auf welchem Prozesor kommt für a == 4 raus, und es werden trotzdem
> 4x16Bit Speicher belegt? ;-)

Ich vermute auf irgendeinem DSP?

von Stefan F. (Gast)


Lesenswert?

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 ?

von Falk B. (falk)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

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

von Axel S. (a-za-z0-9)


Lesenswert?

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

von Walter T. (nicolas)


Lesenswert?

Axel S. schrieb:
> [...]

Hui, Du bist ja auch wieder hier aktiv. Kann man zum neuen Rufzeichen 
gratulieren?

von m.n. (Gast)


Lesenswert?

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 durchaus

Axel S. schrieb:
> Genauso gut könnte ein solcher Compiler

Axel S. schrieb:
> Im Gegenzug könnte man

Axel 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!

von Holger K. (holgerkraehe)


Lesenswert?

Ich habe das ganze nun im MemoryBrowser des STM angeschaut.
Die Initialisierten Bytes des uint8_t arrays liegen direkt 
hintereinander, ohne padding bits.

Danke

von Jim M. (turboj)


Lesenswert?

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.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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.

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.