Forum: Compiler & IDEs Struct Hilfe


von sascha_focus (Gast)


Lesenswert?

Hallo zusammen,

habe ein struct angelegt. Bestehend aus mehreren Statusbits.

typedef struct {
    unsigned ENABLE                 :1;
    unsigned RESET                  :1;
    unsigned NEW                    :1;
    unsigned EN                     :1;
    unsigned MODE                   :3;
    unsigned MODE2                  :1;
    unsigned UP                     :1;
    unsigned DOWN                   :1;
    unsigned DIRECT                 :1;
    unsigned STAT                   :1;
    unsigned MUX                    :1;
    unsigned CHANNEL                :3;
}CFG;

Zusammengerechnet ergibt dies zwei Bytes. Nun möchte ich zum Beispiel 
das
definierte Struct in eine 16Bit Variable kopieren. Nun suche ich eine 
Möglichkeit, dem Compiler mitzuteilen, das mein Struct auch da 
reinpasst.

Gruß Sascha

von sascha_focus (Gast)


Lesenswert?

Sorry,

sollte unsigned char sein

von g457 (Gast)


Lesenswert?

> Nun suche ich eine Möglichkeit, dem Compiler mitzuteilen, das mein
> Struct auch da reinpasst.

Das brauchst Du ihm nicht zu sagen, das weiss der auch so. Ich vermute 
Du suchst was anderes: Wenns standardwidrig sein darf man union, sonst 
man 3 memcpy.

von Niklas Gürtler (Gast)


Lesenswert?

Möchtest du die Daten über eine Kommunikations Schnittstelle abschicken 
oder abspeichern? Dann geht das nicht direkt, da C(++) das Layout von 
Bitfeldern nicht definiert. Unter Serialisierung ist das mit Lösung 
erläutert.

von sascha_focus (Gast)


Lesenswert?

Kommunikations Schnittstelle ist korrekt. Es geht um SPI. Wie würde 
sowas denn mit dem Union aussehen?

Gruß Sascha

von MWS (Gast)


Lesenswert?

sascha_focus schrieb:
> Nun suche ich eine
> Möglichkeit, dem Compiler mitzuteilen, das mein Struct auch da
> reinpasst.

__attribute__((packed))

wär' zu erwähnen.

von S. R. (svenska)


Lesenswert?

sascha_focus schrieb:
> Kommunikations Schnittstelle ist korrekt. Es geht um SPI. Wie würde
> sowas denn mit dem Union aussehen?

Ungefähr so:
1
typedef union {
2
  uint16_t alles;
3
  struct bits {
4
    unsigned ENABLE                 :1;
5
    unsigned RESET                  :1;
6
    unsigned NEW                    :1;
7
    unsigned EN                     :1;
8
    unsigned MODE                   :3;
9
    unsigned MODE2                  :1;
10
    unsigned UP                     :1;
11
    unsigned DOWN                   :1;
12
    unsigned DIRECT                 :1;
13
    unsigned STAT                   :1;
14
    unsigned MUX                    :1;
15
    unsigned CHANNEL                :3;
16
  };
17
}CFG;

Die saubere Lösung besteht darin, die Bits einzeln an zentraler Stelle 
ein- und auszupacken:
1
uint16_t encode(CFG x) {
2
  uint16_t tmp = 0;
3
  if(x.ENABLE) tmp |= 0x0001;
4
  if(x.RESET)  tmp |= 0x0002;
5
  /* usw */
6
  return tmp;
7
}
8
9
CFG decode(uint16_t x) {
10
  CFG x;
11
  memset(&x, 0, sizeof(CFG));
12
  if(uint16_t & 0x0001) x.ENABLE = 1;
13
  if(uint16_t & 0x0002) x.RESET  = 1;
14
  /* usw */
15
  return x;
16
}

Dann kannst du statt einzelnen Bits auch bool benutzen und mit 
"true"/"false" arbeiten. Manche Compiler mögen das lieber.

Damit garantierst du, dass es überall funktioniert und du hast das 
Datenformat gleichzeitig eindeutig definiert. Schnittstellen gehören 
immer sauber definiert.

Normalerweise bin ich für die Union-Lösung, aber in deinem Fall ist sie 
absolut ungeeignet. Was man innerhalb seines Programms macht, bleibt 
einem selbst überlassen, aber in dem Moment, wo Kommunikation 
stattfindet, lässt man das besser sein.

von Niklas Gürtler (Gast)


Lesenswert?

Die Union Lösung ist halt in C Implementation defined d.h. unportabel, 
und in C++ komplett verboten. Daher ist die 2. Lösung mit den 
Bit-Operationen deutlich besser. Da ist nur ein Tippfehler  - es sollte 
wohl "x" statt uint16_t heißen

von S. R. (svenska)


Lesenswert?

Niklas Gürtler schrieb:
> Da ist nur ein Tippfehler  - es sollte
> wohl "x" statt uint16_t heißen

Das ist vollkommen korrekt. ;-)
Und statt "x" zweimal zu vergeben, sollte man vielleicht eins davon 
anders benennen. Aber hey, wofür hat man Compiler. ;-)

: Bearbeitet durch User
von Schon 100 mal (Gast)


Lesenswert?

g457 schrieb:
>> Nun suche ich eine Möglichkeit, dem Compiler mitzuteilen, das
> mein
>> Struct auch da reinpasst.
>
> Das brauchst Du ihm nicht zu sagen, das weiss der auch so. Ich vermute
> Du suchst was anderes: Wenns standardwidrig sein darf man union, sonst
> man 3 memcpy.

Union geht nicht. Wenn doch, dann zuvall

von A. S. (Gast)


Lesenswert?

WENN es für eine konkrete Plattform ist,
UND du deinen Compiler kennst
UND konfigurierst
UND Du entsprechende asserts einbaust,
DANN kannst Du Unions verwenden.

Unions sind halt im Zugriff ausdrucksstärker als die portablen Aufsätze. 
Ja, in 10 Jahren wird man dir das vorwerfen, ... hättest Mal sofort 
richtig gemacht, .... Die Pharisäer, die alles richtig machen und bei 
deren Software keiner Änderung braucht.

von Schon 100 mal (Gast)


Lesenswert?

Schwachsinn, nicht in 100 Jahren, sondern heute. Code sollte soweit wie 
möglich portablen gehalten werden. Für die Aufgabe gibt es einfache 
Alternativen. Warum dann so einen sch.. machen?

Mach es gleich richtig, kostet nichts und tut nicht weh. ?

von A. S. (Gast)


Lesenswert?

Schon 100 mal schrieb:
> Code sollte soweit wie möglich portablen gehalten werden.

Portabler Code, ja. Bei HW- oder plattformspezifischem Code nein. Ein 
Registerlayout mit structs (statt diesem 1<<PIN1) ist besser les- und 
statisch analysierbar.


Schon 100 mal schrieb:
> Mach es gleich richtig, kostet nichts und tut nicht weh.
Dann zeig doch Mal eine Lösung, die nicht viel kostet und wartbar ist 
(wartbar im Sinne von an einer Stelle)

Oh, sorry, meinte eigentlich kann structs verwenden, aber das Fass ist 
ähnlich. Ob der TO Unions braucht, wissen wir ja nicht.

von Niklas Gürtler (Gast)


Lesenswert?

Achim S. schrieb:
> Dann zeig doch Mal eine Lösung, die nicht viel kostet und wartbar ist
> (wartbar im Sinne von an einer Stelle)

https://erlkoenig90.github.io/uSer-doc/html/tutorial.html#ConWidth

von S. R. (svenska)


Lesenswert?

Achim S. schrieb:
>> Mach es gleich richtig, kostet nichts und tut nicht weh.
> Dann zeig doch Mal eine Lösung, die nicht viel kostet und wartbar ist
> (wartbar im Sinne von an einer Stelle)

Hab ich doch schon gemacht, Fipptehler inklusive?
Oder wie würdest du das anderweitig machen?

von Schon 100 mal (Gast)


Lesenswert?

Die vorgeschlagene Union Variante ist natürlich Groten–schlecht. Auch 
wenn sie auf den ersten Blick funktioniert, hat es nichts - aber auch 
gar nichts - mit C Programmierung zu tun.
Es wäre nur eine zufällige, vom Compiler geduldete, Ausfuehrung.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hier noch ein Beispiel, wie die Aufgabenstellung mit der µSer-Bibliothek 
umgesetzt werden kann:
1
#include <iostream>
2
#include <cstdint>
3
#include <uSer/uSer.hh>
4
5
struct CFG {
6
  USER_STRUCT (CFG)
7
  USER_MEM(std::uint8_t, ENABLE, uSer::Width<1>)
8
  USER_MEM(std::uint8_t, RESET, uSer::Width<1>)
9
  USER_MEM(std::uint8_t, NEW, uSer::Width<1>)
10
  USER_MEM(std::uint8_t, EN, uSer::Width<1>)
11
  USER_MEM(std::uint8_t, MODE, uSer::Width<3>)
12
  USER_MEM(std::uint8_t, MODE2, uSer::Width<1>)
13
  USER_MEM(std::uint8_t, UP, uSer::Width<1>)
14
  USER_MEM(std::uint8_t, DOWN, uSer::Width<1>)
15
  USER_MEM(std::uint8_t, DIRECT, uSer::Width<1>)
16
  USER_MEM(std::uint8_t, STAT, uSer::Width<1>)
17
  USER_MEM(std::uint8_t, MUX, uSer::Width<1>)
18
  USER_MEM(std::uint8_t, CHANNEL, uSer::Width<3>)
19
20
  USER_ENUM_MEM(ENABLE, RESET, NEW, EN, MODE, MODE2, UP, DOWN, DIRECT, STAT, MUX, CHANNEL)
21
};
22
23
24
int main () {
25
  std::uint16_t raw [1];
26
  CFG myCfg { 1, 1, 1, 0, 3, 0, 0, 0, 0, 0, 0, 4 };
27
  uSer::serialize (raw, myCfg);
28
  
29
  std::cout << "0x" << std::hex << std::setw(4) << std::setfill('0') << raw [0] << std::endl;
30
}

Mehr Schreibarbeit als eine Union, aber dafür portabel und 
wohldefiniert.

von A. S. (Gast)


Lesenswert?

S. R. schrieb:
> Hab ich doch schon gemacht, Fipptehler inklusive?

Ja, aber da muss ich zum enum noch 2 konvertierungsroutinen schreiben. 
Statt einmal den Compiler zu konfigurieren. Bei 5 structs vielleicht 
noch OK. Oder für einen Plattformunabhangigen Treiber.

> Oder wie würdest du das anderweitig machen?
Ja. Structs + asserts.

Zudem ist es überhaupt nicht klar, ob der TO die Struktur überhaupt zu 
anderen kommuniziert oder nur in einem seriellen eeprom speichert oder 
dessen Bits manipuliert.

von S. R. (svenska)


Lesenswert?

Achim S. schrieb:
> Ja, aber da muss ich zum enum noch 2 konvertierungsroutinen schreiben.

Das macht man einmal nach Spec und gut ist. Allein die Verifikation des 
Datenformats mit dem aktuellen Compiler (plus die Asserts) würde 
vermutlich länger dauern als die beiden Routinen zu schreiben.

> Bei 5 structs vielleicht noch OK.
> Oder für einen Plattformunabhangigen Treiber.

Wenn du 200 solcher Structs hast, dann ist die Lage ein bisschen anders, 
zugegeben. Allerdings - und damit hab ich oft genug zu tun - hast du 
dann meist noch ganz andere Probleme. Oder es handelt sich um 
generierten Code, dann kann man die Routinen auch gleich mit generieren 
lassen.

von A. S. (Gast)


Lesenswert?

Schon 100 mal schrieb:
> Es wäre nur eine zufällige, vom Compiler geduldete, Ausfuehrung

Naja, den Zufall kann man hier auch sicherstellen.

Die vorgeschlagenen Lösungen sind halt alle schwer wartbar, also write 
only. Für portable Treiber OK, z.b.ein TCP/IP Stack. Für Systeme, die 
sich laufend weiter entwickeln, sind die Kosten enorm und müssen mit 
einkalkuliert werden. Und allignment und endianess kommen ja nochmal 
oben drauf, und n Bits im Byte, ....

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Achim S. schrieb:
> Naja, den Zufall kann man hier auch sicherstellen.

Indem man bloß nie die Plattform/Compiler-Version/Optionen ändert und 
auch noch in 20 Jahren den gleichen Controller nutzt?

Achim S. schrieb:
> Und allignment und endianess kommen ja nochmal
> oben drauf, und n Bits im Byte, ....

Ganz genau das ist das Problem der Union. Genau deshalb sollte man es 
lieber mit bitweisen Operationen machen.

Achim S. schrieb:
> Die vorgeschlagenen Lösungen sind halt alle schwer wartbar, also write
> only.
Ich finde meine Lösung ist hinreichend gut wartbar. Die Syntax ist etwas 
wortreich, aber es ist simpel, das Format anzupassen.

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.