Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 17 Strukturen
  gp 17.1 Struktur deklarieren
  gp 17.2 Initialisierung und Zugriff auf Strukturen
  gp 17.3 Strukturen als Wertübergabe an eine Funktion
  gp 17.4 Strukturen als Rückgabewert einer Funktion
  gp 17.5 Strukturen vergleichen
  gp 17.6 Arrays von Strukturen
  gp 17.7 Strukturen in Strukturen (Nested Structures)
  gp 17.8 Kurze Zusammenfassung zu den Strukturen
  gp 17.9 Union
  gp 17.10 Aufzählungstyp enum
  gp 17.11 Typendefinition mit typedef
  gp 17.12 Attribute von Strukturen verändern (nicht ANSI C)
  gp 17.13 Bitfelder
  gp 17.14 Das offsetof-Makro


Galileo Computing - Zum Seitenanfang

17.13 Bitfelder  toptop

Bitfelder sind Strukturelemente, die mit weniger als 1 Byte in eine Struktur gepackt werden können. Laut ANSI C müssen die einzelnen Elemente von Bitfeldern vom Datentyp int oder unsigned int sein.

Als Beispiel soll hier ein Roboter für eine Fließbandproduktion programmiert werden. Der Roboter muss ein bestimmtes Produkt von Position A nach Position B transportieren. Hier die einzelnen Arbeitsabläufe, die dazu erforderlich sind:

1. Produkt zum Befördern vorhanden (Sensor 1 = aktiv). Wenn ja …
       
2. Produkt erfassen und hochheben und auf das Fließband legen. Wenn Produkt auf Fließband liegt (Sensor 2 = aktiv), dann ...
       
3. Fließband bewegen (Schalter 1) und warten, bis Produkt beim Sensor 3 ankommt. Dann wieder prüfen, ob ein Produkt auf Sensor 1 vorhanden ist. Falls an Sensor 1 ein Produkt vorhanden ist, alles wieder von vorn.
       

Dieser Vorgang soll auch überprüft werden, und bei einem Fehler wird ein Fehlercode ausgegeben, für den es eine entsprechende Stringtabelle gibt. Außerdem wird dazu eine Anzeige benötigt. Es wird davon ausgegangen, dass der Roboter bereits mit dem PC verbunden ist. Hier die Struktur des Roboters:

struct robo {
   unsigned char sensor1;
   unsigned char sensor2;
   unsigned char sensor3;
   unsigned char schalter;
   int Ausgabe;
} Roboter1;

Abgesehen davon, dass dies in ANSI C nicht erlaubt ist, benötigt der Roboter mit dieser Struktur 48 Bits (6 Bytes). Wenn jetzt noch mehrere Roboter hinzukommen, ist das eine Speicherplatzverschwendung. Häufig ist bei solchen Automatisierungs-Robotern nicht unbegrenzt Speicherplatz vorhanden. Bei den Sensoren und Schaltern benötigen Sie in der Regel nur zwei Schaltstellungen: 1 für betätigt und 0 für unbetätigt. In C ist es auch möglich, einzelne Bits einer Struktur anzusprechen. Hier die entsprechende Struktur:

struct robo {
   unsigned sensor1:1;
   unsigned sensor2:1;
   unsigned sensor3:1;
   unsigned schalter:1;
   unsigned Ausgabe:4;
} Roboter1;

Jetzt benötigt die Struktur nur noch acht Bits (ein Byte). Der Trick ist eigentlich ganz einfach: Es wurde hier das Schlüsselwort unsigned benutzt, das intern im Prozessor auf 0 gesetzt ist. Das Schlüsselwort unsigned benötigt ein Bit, und mit einem Bit kann man den Wert 1 oder 0 darstellen. Die Variablen-Ausgabe enthält vier Bits, womit eine Zahl bis 16 dargestellt werden kann (2*2*2*2).

Hier das Beispiel dazu:

/* bitfields.c */
#include <stdio.h>
#include <stdlib.h>
enum{ OFF, ON };
struct robo {
   unsigned Sensor1:1;
   unsigned Sensor2:1;
   unsigned Sensor3:1;
   unsigned Schalter:1;
   unsigned Ausgabe:4;
} Roboter1;
char *msg[7] = {
   "Kein Signal an Sensor 1!\n",
   "Kein Signal an Sensor 2!\n",
   "Kein Signal an Sensor 3!\n",
   "Schalter 1 nicht betätigt!\n",
   "Notaus betätigt!\n",
   "Kein Strom!\n"
};
int main(void) {
   int anzahl;
   do {
       printf("Wie viele Produkte von Pos.A nach Pos.B : ");
       do{ scanf("%d",&anzahl); } while(getchar() != '\n');
       while((anzahl>0) && (anzahl--)) {
          /* Sollte durch echte Schnittstelle ersetzt werden */
          Roboter1.Sensor1=ON;
          printf("Sensor 1 ist aktiv\n");
          if(Roboter1.Sensor1 == ON)
             printf("Produkt wird aufgenommen und "
                    "zum Fließband transportiert\n");
          else {
             /* Fehler Sensor 1 nicht aktiv
              * Fehlermeldung ausgeben */
             Roboter1.Ausgabe = 0;
             printf("%s\n", msg[Roboter1.Ausgabe]);
          }
            /* Sollte durch echte Schnittstelle ersetzt werden */
             Roboter1.Sensor2=ON;
             printf("Sensor 2 ist aktiv\n");
             if(Roboter1.Sensor2 == ON) {
                printf("Produkt ist auf dem Fließband\n");
                printf("Bitte >>ENTER<< drücken"
                       " für den Schalter\n");
                getchar();
                printf("Schalter ist eingeschaltet!\n");
                /* Sollte durch echte Schnittstelle
                 * ersetzt werden */
                Roboter1.Schalter=ON;
             }
             else {
                Roboter1.Ausgabe=1;
                printf("%s\n",msg[Roboter1.Ausgabe]);
                Roboter1.Ausgabe=3;
                printf("%s\n", msg[Roboter1.Ausgabe]);
             }
             /* Sollte durch echte Schnittstelle
              * ersetzt werden */
             Roboter1.Sensor3=ON;
             printf("Sensor 3 aktiv\n");
             if(Roboter1.Sensor3 == ON) {
                printf("Produkt am Ziel angekommen!\n");
                printf("Schalter für Fließband auf OFF\n");
                printf("Roboter wieder betriebsbereit\n");
                printf("Weiter mit >>ENTER<<\n");
                getchar();
                Roboter1.Schalter=OFF;
             }
             else {
                Roboter1.Ausgabe = 2;
                printf("%s\n", msg[Roboter1.Ausgabe]);
             }
       }
   } while(anzahl > 0);
   Roboter1.Sensor1=OFF;
   Roboter1.Sensor2=OFF;
   Roboter1.Sensor3=OFF;
   Roboter1.Ausgabe=0;
   printf("%s\n",msg[Roboter1.Ausgabe]);
   return EXIT_SUCCESS;
}

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 17.11   Der Roboter im Einsatz

Dass die Struktur robo hier vier Bytes anstatt einem Byte groß ist, liegt am Alignment des Betriebssystems. Hier kann der Speicherplatz mit dem Keyword attribute oder dem Pragma pack auf ein Byte zusammengepackt werden. Vorausgesetzt, der Compiler unterstützt dies:

//#pragma pack(1)
struct robo {
   unsigned Sensor1:1;
   unsigned Sensor2:1;
   unsigned Sensor3:1;
   unsigned Schalter:1;
   unsigned Ausgabe:4;
} __attribute__ ((packed)) Roboter1;

Diese Struktur nochmals bildlich:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 17.12   Bitbelegung der einzelnen Bitfelder der Struktur robo

Das Dumme an diesem Beispiel ist, dass es zu gar nichts taugt, da keine Verbindung mit einem Roboter besteht. Zeilen wie

Roboter1.Sensor1=ON;
Roboter1.Sensor2=ON;

müssen selbst eingegeben werden.

Daher folgt ein ausführbares Beispiel, welches zeigt, was eine Schnittstelle bzw. eine Adresse zum PC genau ist. Es wird der Druckerstatus am Port LPT1 überprüft. Das Listing ist nur unter MS-DOS ausführbar und nicht ANSI C-konform:

/* check_printer.c */
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
/* 0x378 ist die Adresse der Schnittstelle von LPT1 */
#define LPT1_PORT 0x378
struct status {
   unsigned        :3;     /* Bit 0–2 nicht verwendet */
   unsigned fehler :1;     /* 0=Druckerfehler         */
   unsigned online :1;     /* 1=Drucker online        */
   unsigned papier :1;     /* 1=kein Papier           */
   unsigned empfang:1;     /* Emfangsbestätigung      */
   unsigned busy   :1;     /* Drucker bereit          */
} LPT1_status;
/* Status am LPT1-Port auslesen */
void druckerstatus(char *statuszeiger) {
   *statuszeiger = inp( LPT1_PORT+1 ) & 0xF8;
}
int main(void) {
   druckerstatus( (char *) &LPT1_status);
   if(LPT1_status.busy && LPT1_status.online) {
      printf("Drucker ist bereit!\n");
      return EXIT_SUCCESS;
   }
   else if(!LPT1_status.online)
      printf("Drucker nicht online!\n");
   else if(LPT1_status.papier)
      printf("Kein Papier vorhanden!\n");
   else
      printf("Drucker ist nicht bereit!\n");
   return EXIT_SUCCESS;
}

Die Adresse 0x378 stellt die Adresse des Ports LPT1 dar. Das Statusregister, das hier überprüft wird, sieht intern aus, wie in Abbildung 17.13 beschrieben.

Diese Struktur ähnelt der Struktur, die oben bei den Robotern verwendet wurde. Die Bits 0–2 werden nicht verwendet. Die Bits 3–7 geben anschließend den Status des Druckers zurück. Je nachdem, welche Bits gesetzt sind und welche nicht. Die Funktion druckerstatus() liefert den Status zurück. Neu ist bei diesem Programm:

unsigned:3;

Hiermit werden drei Bits ohne Namen definiert. Im Beispiel sind es die ersten drei Bits, die ungenutzt bleiben. Sie können im Programm nicht verwendet werden und werden als anonyme Bitfelder bezeichnet.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 17.13   Bitbelegung eines Druckers am LPT1-Port unter MS-DOS

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de