www.mikrocontroller.net

Forum: Compiler & IDEs Agregat in C


Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aus VHDL kenne ich sogenannte Aggregate.
Habe mal ein Beispiel gemacht:
Mein_Aggregat <= (10,Bla7,Bla5,Bla3,Bla1,10);


In C habe ich Bitfelder in einer struct,
hier ein Beispiel:
struct {
   unsigned Bla0:1;
   unsigned Bla1:1;
   unsigned Bla2:1;
   unsigned Bla3:1;
   unsigned Bla4:1;
   unsigned Bla5:1;
   unsigned Bla6:1;
   unsigned Bla7:1;
} Mein_Status;

Wie kann ich in C Statusbits aus verschiedenen Struct's zusammenfassen 
wie in VHDL in einem Aggregat?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zauberlehrling schrieb:

> Wie kann ich in C Statusbits aus verschiedenen Struct's zusammenfassen

Du meinst automatisch?

Gar nicht.

> wie in VHDL in einem Aggregat?

Ich glaube nicht, dass sich die beiden Konzepte entsprechen.

Autor: Zappelphilipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Ich glaube nicht, dass sich die beiden Konzepte entsprechen.
>

Mir ist schon klar, das es so einfach nicht geht.
Ich kann es natürlich mit viel maskieren und schieben hinkriegen, hier 
einmal ein Beispiel:
Mein_Send_Byte = 0b10000010 
                | ((Bla & 0x01) << 5)
                | ((Bla & 0x04) >> 2)
                | ((Bla & 0x10) >> 1)
                | ((Bla & 0x40) >> 4);

Nur möchte ich zur besseren Lesbarkeit es so haben wie in VHDL mit dem 
Aggregat.
Kann man den Leuten, die C weiterentwickeln, sowas nicht vorschlagen.
Wie heisst denn dieses Kommitee, das den Standart von C89 und C99 
festgelegt hat.
Gibt es vieleicht bald ein C2011?

Autor: Zappelphilipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf so Bitfelder greife ich z.B. so zu:
if (Mein_Status.Bla3 && Mein_Status.Bla7) mach_was;

Habe ich da noch andere Möglichkeiten?


BTW. bevor noch jemand verwirrt ist: Zauberlehling = Zappelphillip  ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zappelphilipp schrieb:

> Mir ist schon klar, das es so einfach nicht geht.
> Ich kann es natürlich mit viel maskieren und schieben hinkriegen, hier
> einmal ein Beispiel:
>
> Mein_Send_Byte = 0b10000010
>                 | ((Bla & 0x01) << 5)
>                 | ((Bla & 0x04) >> 2)
>                 | ((Bla & 0x10) >> 1)
>                 | ((Bla & 0x40) >> 4);
> 
>
> Nur möchte ich zur besseren Lesbarkeit es so haben wie in VHDL mit dem
> Aggregat.

Mach dir eine Funktion, die die Details versteckt und gut ists.
Letzten Endes: Ob du das schieben explizit machst oder ob du es dem 
Compiler aufzwingst, ist für den Prozessor gehupft wie gesprungen.

Du kannst natürlich machen:
  Mein_Status alt1, alt2;   // von diesen beiden einige Bits ...
  Mein_Status neu;          // ... hierher zusammenkopieren

  neu.Bla1 = alt_1.Bla5;
  neu.Bla2 = alt_1.Bla7;
  neu.Bla3 = alt_2.Bla4;

  etc.

aber letzten Endes mündet auch das in Verschieben und Verodern :-)

> Kann man den Leuten, die C weiterentwickeln, sowas nicht vorschlagen.

Kann man.
Aber wozu? Das was du willst kannst du erreichen. 
Sprachweiterentwicklungen nur damit du dir 3 Zeilen Tipparbeit sparst, 
die ausser dir niemand braucht, da wird sich kaum eine Mehrheit dafür 
finden :-)

Autor: Zappelphilipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Sprachweiterentwicklungen nur damit du dir 3 Zeilen Tipparbeit sparst,

Naja, der Wunsch, ein paar Zeilen Tipparbeit zu sparen (und natürlich 
Portierbarkeit) waren afaik die Hauptantriebsfedern, überhaupt 
Hochsprachen zu entwickeln  ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zappelphilipp schrieb:
> Karl heinz Buchegger schrieb:
>> Sprachweiterentwicklungen nur damit du dir 3 Zeilen Tipparbeit sparst,
>
> Naja, der Wunsch, ein paar Zeilen Tipparbeit zu sparen (und natürlich
> Portierbarkeit) waren afaik die Hauptantriebsfedern, überhaupt
> Hochsprachen zu entwickeln  ;-)

OK. Mach einen Vorschlag.
Wie sollte eine derartige Erweiterung deiner Meinung nach aussehen?

Aber diesmal bitte ganz konkret.
Wie soll die C-Syntax aussehen? Welche Aktion soll erfolgen? Am besten 
demonstriertst du das alles in einem hypotetischen Programm, welches 
dein neues Sprachfeature nutzt.

Und ach ja: neue Schlüsselwörter sind im C-Kommitee gar nicht gerne 
gesehen. Wenn geht, benutz vorhandene Schlüsselwörter.

Ich spiel Normungsgremium und seh mir den Vorschlag an.
Bedenke aber, dass du mit Aussagen wie in deinem Eröffnungsposting (wie 
in VHDL) nicht durchkommen wirst. Das musst du mir schon konkreter 
verkaufen.

Autor: Zappelphilipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Ich spiel Normungsgremium und seh mir den Vorschlag an.

Meine Freundin hat eben angerufen, will mit mir baden gehen...
deshalb schlunze ich das mal eben so aif die Schnelle zusammen:

Ein Programmfragment könnte z.B. so aussehen:
struct {
   unsigned Bla0:1;
   unsigned Bla1:1;
   unsigned Bla2:1;
   unsigned Bla3:1;
   unsigned Bla4:1;
   unsigned Bla5:1;
   unsigned Bla6:1;
   unsigned Bla7:1;
} Mein_Status;

struct {
   unsigned Bla0:1;
   unsigned Bla1:1;
   unsigned Bla2:1;
   unsigned Bla3:1;
   unsigned Bla4:1;
   unsigned Bla5:1;
   unsigned Bla6:1;
   unsigned Bla7:1;
} Dein_Status;

Mein_Aggregat = {['1','0',Mein_Status.Bla7,
                          Dein_Status.Bla5,
                          Mein_Status.Bla7,
                          Dein_Status.Bla5,
                          '1','0']};

RF_put_char(Mein_Aggregat);

Ich bin dann mal weg ;-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mein_Aggregat =

Mein_Aggregat ist ja nicht einmal definiert worden.

Ein wenig C-Syntax solltest du schon beherrschen, bevor du hier einen
Vorschlag zur Änderung des Standards bringst...  Nein, das schreibt
man nicht mal in 5 Minuten vor dem Badengehen.

"aggregate type" ist im Sinne des C-Standards übrigens ein Überbegriff
für struct/union + arrays.

Autor: faustian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Haelt ihn doch keiner von ab mit einem struct voller vorinitialisierter 
Zeiger zu arbeiten...

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich den Zauberlehrling richtig verstanden habe, kommt seinem Wunsch
Folgendes wahrscheinlich am nächsten:
struct status {
  unsigned int b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

int main(void) {
  struct status st1 = { 1, 1, 0, 1, 0, 0, 1, 1 }, st2;

  st2 = (struct status){ 1, 0, st1.b7, st1.b5, st1.b7, st1.b5, 1, 0 };
  return 0;
}

Das Ganze ist C99-konform und funktioniert natürlich auch über mehrere
unterschiedliche Strukturen hinweg.

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Wenn ich den Zauberlehrling richtig verstanden habe, kommt seinem Wunsch
> Folgendes wahrscheinlich am nächsten:
>
>
> struct status {
>   unsigned int b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
> };
> 
> int main(void) {
>   struct status st1 = { 1, 1, 0, 1, 0, 0, 1, 1 }, st2;
> 
>   st2 = (struct status){ 1, 0, st1.b7, st1.b5, st1.b7, st1.b5, 1, 0 };
>   return 0;
> }
> 
>
> Das Ganze ist C99-konform und funktioniert natürlich auch über mehrere
> unterschiedliche Strukturen hinweg.

Nein, das ist wahrscheinlich nicht, das was der Zauberlehrling meint, 
weil st2 hier nur mit den Werten von st1 initialisiert wird.
Wenn sich st1 ändert, zieht st2 nicht mit.

Bei einem Aggregat in VHDL werden mehrere Objekte zusammengefasst und 
unter einem neuen Namen angesprochen.

So etwas ähnliches wurde meiner Erinnerung nach von Anfängern schon 
mehrmals gewünscht, die gerne verschiedene bestehende Variablen zu einer 
Struct zusammenfassen würden.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich vermute mal, daß es sowas nicht gibt, weil das programmtechnisch ein 
höllisch riesiger Aufwand ist.

Wilst Du 8 Bits aus 8 Variablen lesen und zusammenfassen, sind das 
locker 32 Befehle (je Bit: Variable lesen, Bit maskieren, Bit an die 
Stelle schieben, mit Ergebnis verodern).
Deine CPU wird also zur Schnecke gemacht.

Bei nem FPGA sind das dagegen nur programmierte Verbindungen und das 
Zeitverhalten wird nicht verschlechtert.


Peter

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Falser schrieb:
> Nein, das ist wahrscheinlich nicht, das was der Zauberlehrling meint,
> weil st2 hier nur mit den Werten von st1 initialisiert wird.
> Wenn sich st1 ändert, zieht st2 nicht mit.

Ok, dann eben mit einem Makro ;-)
#include <stdio.h>

struct status {
  unsigned int b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

int main(void) {
  struct status st1 = { 1, 1, 0, 1, 0, 0, 1, 1 };
  #define st2 (struct status){ 1, 0, st1.b7, st1.b5, st1.b7, st1.b5, 1, 0 }

  printf("%d\n", st2.b2); // Ausgabe von st2.b2 -> 1
  st1.b7 = 0;             // Ändern von st1
  printf("%d\n", st2.b2); // Ausgabe von st2.b2 -> 0
  return 0;
}

Allerdings ist diese Methode ziemlicher Pfusch, weil der Scope von st2
nun nicht mehr lokal ist. Soll st2 hingegen global sein, wär's
vielleicht halbwegs akzeptabel.

Nach wie vor arbeitet die Methode auch nicht bidirektional, d.h. eine
Änderung von st2 wirkt sich nicht auf st1 aus, was aber vielleicht
gewünscht wäre.

In C++ hätte man mit der Überladung von Operatoren etwas bessere
Möglichkeiten, so etwas zu realisieren.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht sollte man auch einfach mal von der VHDL-Denkweise runter 
kommen, dass eine Zuweisung (oder in diesem Fall eine Zusammenfassung) 
von Variablen dauerhaft (also nebenläufig) wirkt, sondern in C einfach 
nur einmal ausgeführt wird. So wie man in VHDL Signale mit 
unterschiedlichen Namen einfach verbinden kann, kann man in C nunmal 
keine Variablen verbinden.

Autor: faustian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"kann man in C nunmal keine Variablen verbinden."

Ausser man richtet zwei Zeiger auf die selbe Addresse - mit Bitfields 
geht das aber nicht (weil die hardwaremaessig keine echte Addresse 
haben, ausser ggf auf dem 8051).

Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus schrieb:
> Vielleicht sollte man auch einfach mal von der VHDL-Denkweise runter
> kommen, dass eine Zuweisung (oder in diesem Fall eine Zusammenfassung)
> von Variablen dauerhaft (also nebenläufig) wirkt, sondern in C einfach
> nur einmal ausgeführt wird. So wie man in VHDL Signale mit
> unterschiedlichen Namen einfach verbinden kann, kann man in C nunmal
> keine Variablen verbinden.

Sorry, ich habe es leider nicht geschaft genau zu erklären was ich will.
Neuer Versuch:
Ich will Statusbits die in verschiedenen Struct's vorhanden sind in 
einem Char oder short int zusammenfassen und dann per RS232 oder 
RF-Modul usw. verschicken. Die Aktualisierung brauch natürlich nur kurz 
vor dem verschicken passieren, und nicht wie bei VHDL dauernd.

Autor: Updater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zauberlehrling schrieb:
> Die Aktualisierung brauch natürlich nur kurz
> vor dem verschicken passieren

Dann ruf kurz vor dem Verschicken die Funktion update() auf ;-)

Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Updater schrieb:
> Dann ruf kurz vor dem Verschicken die Funktion update() auf ;-)

Aber das soll nicht so aussehen:
Send_Byte(  0b10000010 
         | ((Bla & 0x01) << 5)
         | ((Bla & 0x04) >> 2)
         | ((Bla & 0x10) >> 1)
         | ((Bla & 0x40) >> 4));

sondern z.B. so:
Send_Byte = {['1','0',St1.B7,St1.B5,St2.B7,St2.B5,'1','0']};

Es soll nur einfach die ganze Maskiererei und Schieberei verborgen 
werden.
Deshalb habe ich gedacht, wenn das nicht geht, dann sollte C2012 diese 
Möglichkeit enthalten.

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zauberlehrling schrieb:
> Deshalb habe ich gedacht, wenn das nicht geht, dann sollte C2012 diese
> Möglichkeit enthalten.

Bitte dann gleich die Möglichkeit zum Gelddrucken, Ferrari fahren, 
Gedankenlesen usw. auch mit einbauen....
Wird dann halt ein Major release :-)

Autor: Frederik Krämer (n0ll4k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann man statt dem Ferrari auch ne Porsche nehmen?

Also dafür das es nur verborgen werden soll ist der Aufwand schon recht 
hoch, ich kann zwar jetzt kein VHDL. Aber ich denke wenn man ne neue 
Programmiersprache lernt sollte man halt auch versuchen mit dem Syntax 
und den gegebenen Möglichkeiten klar zu kommen...

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zauberlehrling schrieb:
> Die Aktualisierung brauch natürlich nur kurz vor dem verschicken
> passieren, und nicht wie bei VHDL dauernd.

Zauberlehrling schrieb:
> Aber das soll nicht so aussehen:Send_Byte(  0b10000010
>          | ((Bla & 0x01) << 5)
>          | ((Bla & 0x04) >> 2)
>          | ((Bla & 0x10) >> 1)
>          | ((Bla & 0x40) >> 4));
>
> sondern z.B. so:Send_Byte = {['1','0',St1.B7,St1.B5,St2.B7,St2.B5,'1','0']};
>
> Es soll nur einfach die ganze Maskiererei und Schieberei verborgen
> werden.

Dann war doch das, was ich oben geschrieben habe, gar nicht so daneben:

Yalu X. schrieb:
>   st2 = (struct status){ 1, 0, st1.b7, st1.b5, st1.b7, st1.b5, 1, 0 };

Bis auf die zusätzliche Typbezeichnung und den fehlenden eckigen
Klammern ist das sogar die gleiche Syntax. Und darauf musst du nicht
einmal bis 2012 oder noch länger warten, das gibt es schon seit 1999.

Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Bis auf die zusätzliche Typbezeichnung und den fehlenden eckigen
> Klammern ist das sogar die gleiche Syntax. Und darauf musst du nicht
> einmal bis 2012 oder noch länger warten, das gibt es schon seit 1999.

@ Yalu:
Danke, du bist ein großer Zauberer, bei dir geh ich gern in die Lehre! 
;-)

Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich schreibe:
#include <avr/io.h>

struct status {
  unsigned int b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

unsigned char Mein_Byte;

int main(void) {
  struct status st1,st2;
  
  st1.b7 = 1;

  st2 = (struct status){ 1, 0, st1.b7, st1.b5, st1.b7, st1.b5, 1, 0 };

  Mein_Byte =  st2;
  return 0;
}

Da bekomme ich leider eine incompatible types in assignment Error.
Was tun?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Fehlermeldung bekommst Du wahrscheinlich hier:

    Mein_Byte =  st2;

Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Die Fehlermeldung bekommst Du wahrscheinlich hier:
>
>     Mein_Byte =  st2;


Stimmt.
unsigned char und struct status passen nicht zusammen.

Was kann man da tun?

Autor: Scherzkeks (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sich eine Funktion schreiben?
unsigned char convert(struct status x)
{
    // wandle um
}

Mein_Byte = convert(st2);

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zauberlehrling schrieb:
> Rufus t. Firefly schrieb:
>> Die Fehlermeldung bekommst Du wahrscheinlich hier:
>>
>>     Mein_Byte =  st2;
>
>
> Stimmt.
> unsigned char und struct status passen nicht zusammen.
>
> Was kann man da tun?



Ähm.
Casten?

Autor: Zauberlehrling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Ähm.
> Casten?
#include <avr/io.h>

struct status {
  unsigned char b0:1;
  unsigned char b1:1;
  unsigned char b2:1;
  unsigned char b3:1;
  unsigned char b4:1;
  unsigned char b5:1;
  unsigned char b6:1;
  unsigned char b7:1;
};

unsigned char Mein_Byte;

int main(void) {
  struct status st1,st2;
  
  st1.b7 = 1;

  st2 = (struct status){ 1, 0, st1.b7, st1.b5, st1.b3, st1.b1, 1, 0 };

  Mein_Byte = (unsigned char)st2;
  return 0;
}

Leider die Fehlermeldung:
aggregate value used where an integer was expected
in der Zeile Mein_Byte = (unsigned char)st2;

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Dann war doch das, was ich oben geschrieben habe, gar nicht so daneben:
> Yalu X. schrieb:
>>   st2 = (struct status){ 1, 0, st1.b7, st1.b5, st1.b7, st1.b5, 1, 0 };

Nur will er das ja dann an ein anderes System übertragen, und da ist 
nicht garantiert, dass eine identisch deklarierte struct auf der 
anderen Seite wirklich Bit für Bit identisch aufgebaut ist. Will man 
Portabilität der Daten erreichen, dann muss man sich schon von Hand auf 
die Ebene der Bits und Bytes begeben.

Andreas

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zauberlehrling schrieb:
> Karl heinz Buchegger schrieb:
>> Ähm.
>> Casten?

> Leider die Fehlermeldung:
> *aggregate value used where an integer was expected*
> in der Zeile Mein_Byte = (unsigned char)st2;

Wo ein Wille, da ein Weg :-)
    Mein_Byte = *(unsigned char*)&st2;

Das heißt aber nicht, das ich das für eine gute Idee halte!

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Wo ein Wille, da ein Weg :-)    Mein_Byte = *(unsigned char*)&st2;

You evil caster you! ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.