Programmieren
 
 
 
 
 
C-Grundkurs
 
 
 
 
 
.. Beispiel: Ganzzahl binär ausgeben
 
 

 
 
 
 

 

Aufgabe:
Zur Ausgabe der Signalzustände von digitalen Toren auf dem Bildschirm, verwendet man die hexadezimale oder die binäre Schreibweise von Zahlen. Aus beiden lassen sich beispielsweise die logischen Werte eines Tores schnell erfassen. Vorteilhaft ist insbesondere die binäre Notation, weil hier jedes Bit in seinem Zustand durch 0 oder 1 angezeigt wird, wodurch dann auch sein elektrischer Status, 0V oder 5V, bekannt ist. Leider gibt es in Bezug auf die Funktion printf() keine Formatierungszeichen %.. für die binäre Ausgabe von Speicherinhalten. Sie wird nur möglich, durch eine eigene Funktion.

Bei dieser Übung soll eine Funktion geschrieben werden, die den Wert eines 8Bit-Speicherinhalts, also eines Bytes, binär ausgibt.

Lösungshinweis:
Zur Verdeutlichung dessen was zu tun ist, kann man sich den Inhalt einer Speicherzelle vorstellen. Angenommen ein Speicherbyte beinhaltet den Wert 9Ah dann würde sich dieser binär wie folgt darstellen ..
                                                       9A = 1001 1010
Genau in dieser binären Form soll der Inhalt des Bytes auf dem Bildschirm erscheinen. Hierzu müssten die Nullen und Einsen des Bytes so isoliert werden, dass sie jeweils alleine in einem Speicher erscheinen um dann mit printf ausgegeben zu werden. Dies könnte mit %u als Zahl, oder mit %c als ASCII-Zeichen geschehen. Bei der Ausgabe ist allerdings zu beachten, dass die äusserst linke Ziffer als erste ausgegeben werden muss, denn der Cursor wandert von links nach rechts und das bedeutet wiederum dass die linke 1 als erste isoliert werden muss, dann die 0, die nächste 0, die nächste 1, usw.

Für das Herausfiltern der Einsen und Nullen gibt es mehrere Wege, die vorrangig auf den Operationen Schieben << (nach links) und/oder >> (nach rechts) und maskieren mit & (bitweises UND) basieren. Da insgesamt 8 Bits isoliert werden müssen ist, zudem ein Schleifenkonstrukt notwendig, das die acht Schiebevorgänge gewährleistet. Auch für die Schleifenbildung gibt es mehrere Möglichkeiten.
Die nachfolgende Realisierung von PrintBinär (prtbin) benutzt die Operationen >> (schiebe nach rechts), & (bitweises UND) sowie eine for-Schleife. Ergründen Sie was hier geschieht.

 

 

 

 

 


 

// prtbin.cpp
// ------------  Version 06.10.2007
//               Borland IDE C++ 3.1 oder 5.02
//               Model:  SMALL
//               Char:   unsigned
//               bearbeitet: www.GoBlack.de, D.Schwarzer

// Hardware:     jeder DOS-PC

#include <stdio>    // für printf()
#include <conio>    // für getch()


// prtbin()
// Zerlegt die in einem Byte (char) oder word (unsigned) übergebene
// Zahl 'byte' in eine Folge von Einsen und Nullen und gibt von
// dieser die unteren acht Bit zum Bildschirm aus.

void prtbin(unsigned byte)
{
  for(char i=0; i<8; i++) printf("%u",(byte>>(7-i))& 0x0001);
}


// main()
// ruft die Funktion prtbin() mit einem Übergabewert, der binär
// dargestellt werden soll, auf und wartet dann auf einen
// Tastendruck.

void main (void)
{
 char zahl = 0x9A;
 printf("Darstellung des Speicherinhalts ..\r\n\n"
        "hexadezimal %Xh = dezimal %u = binär ", zahl, zahl);
 prtbin(zahl);
 getch();
}

 


 

 

 

 

 

zur Funktion main()
main() dient als Testprogramm für die Funktion prtbin(). Dieser wird von hier aus das Byte (char) 9Ah übergeben. Zudem gibt main() zur Kontrolle, die an prtbin() übergebene Zahl, hexadezimal und dezimal zum Bildschirm aus. Dort wird nach dem Durchlauf von main() folgender Text erscheinen ..

                                       Darstellung des Speicherinhalts ..
                                       hexadezimal 9Ah = dezimal 154 = binaer 10011010


zur Funktion prtbin()

Rückgaben:
Die Funktion prtbin() gibt keinen Wert zurück. Sie druckt unmittelbar über printf() zum Bildschirm.

Übergabeparameter:
Die Funktion prtbin() erhält ein Byte übergeben, dessen Inhalt als vorzeichenlose Zahl angesehen werden soll (unsigned char).

Der Körper (body) der Funktion besteht aus einer for-Schleife, die acht mal durchlaufen wird. Dabei sind folgende Besonderheiten zu beachten.
  • Im Kopf der for-Schleife wird die Laufvariable i sowohl deklariert (char i), als auch definiert (i=0). Ansonsten entspricht der Kopf dem Standard der for-Schleife.
  • Der Körper der for-Schleife wird nicht von geschweiften Klammer umschlossen. Dies ist nicht notwendig, da der Körper nur aus einem Befehl, dem Aufruf der Funktion printf() besteht.

Auch bei der printf()-Funktion tritt eine Besonderheit auf. Die im Formatierungsstring an der Stelle %u einzusetzende, vorzeichenlose Zahl muss erst errechnet werden. Anstelle einer Variablen wird hier der Ausdruck byte>>(7-i)& 0x0001 angegeben der vor der Ausgabe durch printf() zunächst ausgerechnet werden muss. Dieses Vorgehen ist bei allen Funktionen der Sprache C erlaubt.
In ausführlicher Weise hätte man prtbin() auch wie folgt programmieren können, was die gedanklich Verfolgung dessen was hier passiert, vereinfacht ..

 

void prtbin(unsigned byte)
{
  char i;
  unsigned tmp=0;

  for(i=0; i<8; i=i+1){
      tmp= byte>>(7-i);
      tmp= tmp&0x0001;
      printf("%u", tmp);
  }
}
 
  • char i;                    es wird die Laufvariable i deklariert.
  • unsigned tmp=0;    es wird eine Hilfsvariable deklariert und initialisiert
  • for (i=0; i<8; i++)  es wird die Startvariable i auf 0 gesetzt, durch die Laufbedingung bestimmt, dass die Schleife so lange durchlaufen werden soll bis i grösser oder gleich 8 ist (also 8 mal) und i nach jedem Durchlauf der Schleife um 1 erhöht wird.
  • tmp=byte>>(7-i);  es wird der Inhalt von byte in ein Prozessorregister kopiert, denn nur hier kann der Schiebevorgang stattfinden. Je nach dem Wert der Laufvariablen i wird der Wert dieses Prozessorregisters 7,6,5,4,3,2,1,0 mal nach rechts geschoben. Damit ist das zu isolierende Bit das niedrigste Bit in dem Prozessorregister, in welches die Variable byte kopiert wurde. Das Ergebnis wird der Variablen tmp abgelegt, denn der Inhalt von byte muss ja für die weiteren Operationen unverändert erhalten bleiben.
  • tmp=tmp&0x0001; es werden alle Bits die noch vor dem zu isolierenden Bit liegen, durch die UND-Maske 0000 0001 auf 0 gesetzt. Nur das unterste Bit bleibt erhalten. Der Inhalt von tmp kann nun 0000 0000 = 0 oder 0000 0001 =1 sein.
  • printf(“%u“, tmp);    es wird der Inhalt von tmp als Dezimalzahl und ohne Vorzeichen ausgegeben. Nach acht Umläufen sind auf diesem Weg alle Bits der Variablen Byte ausgegeben worden.

Die oben noch zerlegten Schritte können zusammengefasst werden. So lässt sich tmp auch mit der Programmzeile tmp= byte>>(7-i)&0x0001 in einem Schritt füllen. Da es zudem in jeder Funktion erlaubt ist ganze Ausdrücke anstelle von einzelnen Variablen zu verwenden, ist es nun möglich die Variable tmp in printf() zu ersetzen. So folgt die Zeile ..
printf(“%u“, byte>>(7-i)&0x0001);
 

 

 

 

 

Ersetzt man übrigens in obigem Programm die 8 durch 16 und die 7 durch 15, lassen sich auch alle 16 Bits des übergebenen Wortes byte, binär darstellen.

 

 


 

 
 
 
 
Varianten
Möchte man das Wandlungsergebnis des Binärwertes in einen Binärstring nicht unmittelbar über printf() zum Bildschirm ausgeben, so kann man den String zunächst in einem Buffer ablegen und die Funktion einen Zeiger auf diesen Buffer zurückgeben lassen.
Dieser String kann dann im aufrufenden Programm beliebig weiterverwendet werden.

Beispiel 1:
 
// bintoa()
// wandelt die Ganzzahl des übergebenen Bytes 'byte' in einen
// nullterminierten String mit binärem ASCII-Code und gibt einen
// Zeiger auf diesen String zurück.

char* bintoa(char byte)
{
  static char binbuf[8+1];           // Buffer auf dem Heap,
                                     // nicht auf dem Stack
  for(signed char n=7; n>=0; n--){
    binbuf[n] = (byte & 0x01);       // unterstes Bit isoliert
    binbuf[n]= binbuf[n]+'0'         // + 30h Versatz im ASCII-Code
    byte=byte>>1;                    // nächstes Bit
  }
  binbuf[8]=0;                       // Buffer nullterminieren
  return(binbuf);
}


// Testprogramm
#include <stdio>    // für printf()
void main(void)
{
  printf("%s", bintoa(0x9A));
}
 

Das obige Beispiel legt den Buffer für den nullterminierten String auf dem Heap an, so dass der erstellte String auch verfügbar bleibt, wenn die Funktion beendet ist. Normale Variable von Unterprogrammen werden auf dem Stack abgelegt und verschwinden von dort wieder, wenn die Funktion beendet wird. Das wäre für den zurückzugebenden String nicht sinnvoll.
Da die Laufvariable n der for-Schleife von 7 nach 0 zurückgezählt wird, muss bei dem Vergleich n<=0 gewährleistet sein, dass nach der 0 negative Zahlen folgen. Dies ist bei unsigned char nicht der Fall, die Schleife würde unendlich laufen. Da der Wertebereich von 'char' in der Voreinstellung des Compilers festgelegt ist und man diese Einstellung nicht zu jedem Zeitpunkt 'im Griff' hat, macht es Sinn, ausdrücklich vorzeichenbehaftete Werte zu verlangen, was durch 'signed char' geschieht. Nun ist die Einstellung des Compilers unbedeutend.
Ansonsten arbeitet das Programm den Wert in 'byte' vom niedrigsten Bit zum höchsten Bit ab, erstellt durch die Addition von 30h den ASCII-Code der 0- und 1-Werte und legt diesen von hinten nach vorne in dem Stringbuffer ab. Am Ende wird der Buffer mit 00h abgeschlossen.

Das folgende Beispiel fasst diesen Prozess in einer Zeile zusammen, berücksichtigt dabei aber unterschiedliche Stringlängen. So können die letzten 4, 8, 16 Bits eines Wortes in den String übertragen werden.

Beispiel 2:
 
 
// bintoa()
// Der Inhalt des übergebenen Speichers 'word' vom Typ unsigned
// wird über die in 'nbit' angegebene Anzahl von Bits in einen
// ASCII -String mit den Zeichen 0 und 1 überführt. Zweckmässige
// Angaben für die Anzahl 'nbit', der auszugebenden Bits können 4,
// 8, 16 lauten. So können binäre Nibble, Bytes oder Words zur
// Ausgabe gewandelt werden. 
// Die Funktion gibt einen Zeiger auf den erstellten, null-
// terminierten String zurück.
char* bintoa(unsigned word, char nbit)
{
 static char binbuf[16+1];

 for(char n=0; n<nbit; n++)binbuf[nbit-1-n]=((word>>n)&0x01)+'0';
 binbuf[nbit]=0;
 return(binbuf);
}
 
 
 
www..de