Kann ich in C ein Array von Unions anlegen und wie greife ich darauf zu?
Ich hab es so probiert:
typedef union
{
uint16_t i16;
struct
{
uint8_t l;
uint8_t h;
}i8;
} un_i16;
volatile un_i16 ust1_data[30];
folgender Zugriffsveruch klappt nicht:
SSP1BUF=ust1_data.i8.h[3];
Was tun?
Doch, seine Art, auf beide Byte zuzugreifen kostet keine Rechenzeit und
verbraucht minimal Speicherplatz.
Das kann man bei Deiner (insbesonder die Highbytevariante) nicht
behaupten.
Punktrichter wrote:
> Doch, seine Art, auf beide Byte zuzugreifen kostet keine Rechenzeit und> verbraucht minimal Speicherplatz.> Das kann man bei Deiner (insbesonder die Highbytevariante) nicht> behaupten.
Nein, weil das Ergebnis seiner Art nirgendwo festgelegt ist und
Plattform und Compiler abhängig ist.
Peter's Art verbraucht "normal" optimiert vermutlich genausolange - aber
man hat kein Problem mehr mit Compilerabhängigem Gedönsel
> aendert sich was, wenn x und y auch als volatile deklariert werden?
ja, es kommt jedesmal eine instruction dazu, weil der zugriff auf die
variablen ja jedesmal neu erfolgen muss.
btw, am besten siehts aus, wenn man die variablen nicht in der funktion
hat:
1
26 a = x.i8.l;
2
\ 00000014 0010D0E5 LDRB R1,[R0, #+0]
3
\ 00000018 0410C0E5 STRB R1,[R0, #+4]
4
27 b = x.i8.h;
5
\ 0000001C 0110D0E5 LDRB R1,[R0, #+1]
6
\ 00000020 0510C0E5 STRB R1,[R0, #+5]
7
28
8
29 c = y & 0xff;
9
\ 00000024 3410A0E3 MOV R1,#+52
10
\ 00000028 0610C0E5 STRB R1,[R0, #+6]
11
30 d = y >> 8;
12
\ 0000002C 1210A0E3 MOV R1,#+18
13
\ 00000030 0710C0E5 STRB R1,[R0, #+7]
kein shift und keine und-verknüpfung.
globale/statische objekte mögen wohl alle compiler lieber ;-)
Mich würde mal interessieren welcher Compiler den in der Praxis Probleme
mit der union Variante hat.
Ich benutze eigentlich auch immer die union Variante.
Die für mich entscheidenden Vorteile:
- Garantiert eine kurze Laufzeit (unabhängig von Qualität des
Compilers...)
- Deutlich übersichtlicher als die mask/shift Variante.
- Bisher hatte ich noch keine Probleme ;)
Was ich mir problematisch vorstelle sind big/little endian Systeme.
Aber da habe ich doch das selbe Problem auch beim shiften?
Wenn das Probleme verursacht gewinnt aber auch hier wieder die union
Variante, dann definiert man halt zwei unions, je nach endian.
Beim shiften müsste man alles direkt im Code ändern
> Was ich mir problematisch vorstelle sind big/little endian Systeme.
das ist der hauptgrund, weshalb man es nicht mit unions machen sollte.
> Aber da habe ich doch das selbe Problem auch beim shiften?
nein, shift und andere operatoren sind unabhängig von der internen
repräsentation der daten.
nungut, ich geb mich geschlagen. (avr-)gcc braucht den umweg ueber die
union, um (in diesem fall) effizienten code zu liefern.
das einzige, womit ich nicht einverstanden bin ist die aussage von
simon:
>Peter's Art verbraucht "normal" optimiert vermutlich genausolange - aber>man hat kein Problem mehr mit Compilerabhängigem Gedönsel
unions sind c-standard und nicht "compilerabhaengiges gedoensel". das
man sie benutzen muss, um das gleiche ergebnis wie mit teuren
bezahlkompilern zu erhalten ist aergerlich, aber funktionieren tuts mit
beiden.
so long, déjà vu.
déjà vu wrote:
> unions sind c-standard und nicht "compilerabhaengiges gedoensel".
Ja, unions sind c-standard. Aber nur solange, wie man auf gleichen wegen
die Daten schreibt/liest. (Sprich: über die gleiche member-variable
reinschreibt, wie man rausliest)
Wenn man unterschiedliche Union-member zum schreiben und lesen benutzt
ist das Verhalten nicht mehr im C-Standard definiert.
> unions sind c-standard und nicht "compilerabhaengiges gedoensel".
ja, aber es ist nicht alles genau definiert. der compiler könnte
padding-bytes einsetzen (um zugriffe zu optimieren) und schon passen
deine bytes nicht mehr. unions sind dazu da, speicherplatz zu sparen. so
wie du sie verwendest, ist das verhalten undefiniert (auch wenn's in der
realität oft gut geht).
Peter wrote:
>> Jou, oder mit weniger Funktionalität>> #define MAKEHI(x) ((x) << 8)> hehe, wenn 'x' ein 'char' ist, gibt das immer 0
Mist, da hast du recht.
beide versionen machen die ISR nur laenger, war ja auch nicht anders zu
erwarten. mir gings eigentlich auch um ein universelles #define fuer r-
und l-values. das man das auch "konventionell" schreiben kann, war mir
schon klar. trotzdem danke, dass du dir die muehe gemacht hast, meinen
code umzuschreiben. aber "lesbarer" wirds dadurch nicht wirklich. das
mit dem #define waere halt schoen, da man sich die .u16 sparen koennte.
aber letztlich kommts ja eh nur auf den bytecode an. und den hab ich mir
schon mit komischen c-konstrukten zurechtgebogen ;)
der vollstaendigkeit halber:
> beide versionen machen die ISR nur laenger, war ja auch nicht anders zu> erwarten.
ja, schade :-(
den GCC sollte man eben mit vorsicht geniessen, aber wenn man die tricks
kennt...
Eine eigene Frage?
Dieser Thread ist über 19 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.