maik87
Goto Top

C++ Problem mit Pointer

Hallo zusammen,

C++ ist lange bei mir her - die Pointer ebenfalls.

Dennoch versuche ich mich gerade wieder einzuarbeiten und stoße auf folgendes Problem:

typedef union union_bitfeld
{
    unsigned char value;
    struct bitfeld_4
    {
        unsigned int bit00 : 1;
        unsigned int bit01 : 1;
        unsigned int bit02 : 1;
        unsigned int bit03 : 1;
    } bitfeld;
} ubf4;


ubf4 test;
test.value = 123;


printf("%d" ,test.value);  
Läuft soweit.

Erweitert um:
ubf4 *pTest;
pTest= &test;

printf("%d" ,*pTest.value);  
läuft es nicht mehr!

Was mache ich in der letzten Zeile falsch?

Content-ID: 244221

Url: https://administrator.de/forum/c-problem-mit-pointer-244221.html

Ausgedruckt am: 22.12.2024 um 17:12 Uhr

Maik87
Maik87 21.07.2014 aktualisiert um 13:21:15 Uhr
Goto Top
Wer googlen kann ist klar im Vorteil:

printf("%d" ,*pTest->value);  

Läuft!

Ist es nun noch möglich, die einzelnen bitxx mit einer Schleife zu durchlaufen?
Quasi so etwas:
for(int i = 0; i<4; i++{
  printf("%d" ,*pTest->bit0i);  
}
rubberman
rubberman 21.07.2014 aktualisiert um 22:27:36 Uhr
Goto Top
Hallo Maik87,

es besteht ein Ungleichgewicht in deiner union zwischen value (8 Bit breit) und struct bitfeld_4 (4 Bit breit oder auch nicht, siehe übernächsten Satz). Das heißt, ein Wert von 123 in value lässt sich nicht mehr in deinem struct abbilden (bei 15 ist Schluss). Darüber hinaus erzeugen Bitfelder in einer union laut Standard undefiniertes Verhalten. Anders gesagt, unter Windows scheint es zu funktionieren (weil die Implementierung es zulässt), auf anderen Betriebssystemen kann das ganz anders aussehen und du darfst dich nicht darauf verlassen, dass Microsoft diese Implementierung nicht irgendwann ändert.

Ist es nun noch möglich, die einzelnen bitxx mit einer Schleife zu durchlaufen?
Nein. Die Kurzerklärung: Nach dem Compilieren gibt es keine Variablennamen mehr.
Du kannst aber durchaus mit bitweisen Operatoren arbeiten. In diesem Fall Shift Right (>>) und Bitweises Und (&).

#include <stdio.h>

typedef union union_bitfeld
{
    unsigned char value;
    struct bitfeld_4
    {
        unsigned int bit00 : 1;
        unsigned int bit01 : 1;
        unsigned int bit02 : 1;
        unsigned int bit03 : 1;
    } bitfeld;
} ubf4;

int main()
{
  ubf4 test = {0};
  ubf4 *pTest = NULL;
  int i = 0;

  test.value = 7;
  pTest = &test;

  printf("%u\n", test.value);  
  printf("%u\n\n", pTest->value);  

  printf("%u\n", pTest->bitfeld.bit00);  
  printf("%u\n", pTest->bitfeld.bit01);  
  printf("%u\n", pTest->bitfeld.bit02);  
  printf("%u\n\n", pTest->bitfeld.bit03);  

  for (i = 0; i < 4; ++i)
    printf("%u\n", pTest->value >> i & 1);  

  return 0;
}

Grüße
rubberman
Maik87
Maik87 22.07.2014 um 09:57:48 Uhr
Goto Top
Zitat von @rubberman:

Hallo Maik87,
Hi Rubberman

es besteht ein Ungleichgewicht in deiner union zwischen value (8 Bit breit) und struct bitfeld_4 (4 Bit breit oder auch
nicht, siehe übernächsten Satz). Das heißt, ein Wert von 123 in value lässt sich nicht mehr in deinem struct
abbilden (bei 15 ist Schluss).
Erwischt! Anfangs war es ein 8bit-bitfeld. Da ich aber nur Zahlen zw. 0 und 9 nutzen möchte, habe ich angefangen, den Code einzuschrumpfen. Scheinbar habe ich das Beispiel nicht komplett überarbeitet face-smile


Darüber hinaus erzeugen Bitfelder in einer union laut Standard undefiniertes Verhalten. Anders
gesagt, unter Windows scheint es zu funktionieren (weil die Implementierung es zulässt), auf anderen Betriebssystemen kann
das ganz anders aussehen und du darfst dich nicht darauf verlassen, dass Microsoft diese Implementierung nicht irgendwann
ändert.
Ich liebe es...! Es ging mir aber in dem Fall auch nur ums Verstehen und um eine Notfalllösung. Wird noch überarbeitet!

> Ist es nun noch möglich, die einzelnen bitxx mit einer Schleife zu durchlaufen?
Nein. Die Kurzerklärung: Nach dem Compilieren gibt es keine Variablennamen mehr.
Da lobe ich mir PHP.

Du kannst aber durchaus mit bitweisen Operatoren arbeiten. In diesem Fall Shift Right (>>) und Bitweises Und (&).
Ohje - das schon wieder. Genau damit habe ich gestern paar graue Haare hinzubekommen.

Ich kopiere mal den Schnippsel und versuche mich nochmal!


Danke!

Grüße
Maik87


PS:
Worin unterscheidet sich
#include <stdio.h> und #include <stdio>?
rubberman
rubberman 22.07.2014 aktualisiert um 19:45:22 Uhr
Goto Top
Ohje - das schon wieder. Genau damit habe ich gestern paar graue Haare hinzubekommen.
Oooch, kein Grund für graue Haare.
Bitweise Operationen sind relativ einfach. Voraussetzung ist, dass du dir die Zahlenwerte tatsächlich in ihrer binären Entsprechung vorstellst oder aufschreibst.
Nehmen wir mal mein Beispiel 7 und an der Stelle auch nur die niedrigsten 4 Bit (mehr interessiert dich ja eh nicht). Die binäre Entsprechung wäre 0111. Das rechte Bit ist das niedrigste Bit und immer 2^0. Je nach Bitbreite des verwendeten Typs, folgen dann 2^1, 2^2 etc.

Binär, schnell erklärt:
exponentiell 2^3 | 2^2 | 2^1 | 2^0
dezimal       8  |  4  |  2  |  1
              x  |  x  |  x  |  x
7 binär       0  |  1  |  1  |  1
              ___________________
Produkt       0  |  4  |  2  |  1
Die Summe in der letzten Zeile ergibt 7. Ist soweit also ziemlich simpel.

Das Binary And hat folgende Regeln:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
Jedes einzelne Bit wird entsprechend behandelt.

Beispiel 7 & 1
7       0  |  1  |  1  |  1
&       &  |  &  |  &  |  &
1       0  |  0  |  0  |  1
_       ___________________
1       0  |  0  |  0  |  1
Ergebnis ist 1. Somit haben wir bereits das niedrigste Bit von 7 ermittelt face-wink

Für die restlichen Bits nehmen wir das Shift Right. Dabei werden die Bits eine bestimmte Anzahl nach rechts verschoben. Die selbe Anzahl Nullen wird vorangestellt und die überflüssigen Bits rechts entfernt.

Die Schleife mal durchgespielt, sieht das so aus:
7       0  |  1  |  1  |  1   >> 0
__      ___________________
7       0  |  1  |  1  |  1
&       &  |  &  |  &  |  &
1       0  |  0  |  0  |  1
__      ___________________
1       0  |  0  |  0  |  1

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

7       0  |  1  |  1  |  1   >> 1
__      ___________________
3       0  |  0  |  1  |  1  [  1  ]
&       &  |  &  |  &  |  &
1       0  |  0  |  0  |  1
__      ___________________
1       0  |  0  |  0  |  1

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

7       0  |  1  |  1  |  1   >> 2
__      ___________________
1       0  |  0  |  0  |  1  [  1  |  1  ]
&       &  |  &  |  &  |  &
1       0  |  0  |  0  |  1
__      ___________________
1       0  |  0  |  0  |  1

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

7       0  |  1  |  1  |  1   >> 3
__      ___________________
0       0  |  0  |  0  |  0  [  1  |  1  |  1  ]
&       &  |  &  |  &  |  &
1       0  |  0  |  0  |  1
__      ___________________
0       0  |  0  |  0  |  0
In der linken Spalte siehst du jeweils die dezimalen Entsprechungen.
Gar nicht mal sooo kompliziert, oder?

PS:
Worin unterscheidet sich
#include <stdio.h> und #include <stdio>?
Öhm, hauptsächlich darin, dass es <stdio> nicht gibt. Meinst du <cstdio> ?
Also, der Code den du oben geschrieben hast, ist eigentlich C und nicht C++. Da C aber aus Kompatibilitätsgründen fast vollständig in C++ aufgeht, wurden auch die entsprechenden Funktionen in den C++ Standard übernommen. Nun sollen diese unter C++ aber auch im Standard-Namespace (namespace std) landen. Damit das passiert, includiert man in C++ nicht die C-Header (bspw. stdio.h) sondern deren C++ Entsprechungen (bspw. cstdio). Im selben Stil stdlib.h zu cstdlib etc...

Heißt aber ausdrücklich nicht dass man beliebig C-Code in C++ verwendet. Das ist schlechter Stil und wie gesagt vorrangig aus Kompatibilitätsgründen überhaupt möglich.

Grüße
rubberman
Maik87
Maik87 23.07.2014 aktualisiert um 16:01:22 Uhr
Goto Top
Super,

vielen vielen Dank für die ausführliche Erklärung!!

Habe meinen Fehler beim bitshifting gefunden face-smile Anfänger!!
Ich habe die Zahl zunächst in binär umgewandelt (z.B. 5 -> 0101), in einem string gespeichert und bin dann mit der Schleife dadurch. Dabei geht das viiiiieeeeel einfacher und ich kann nun eine Menge Code auf dem uC einsparen face-smile


Noch etwas:
Im Endeffekt möchte ich anhand des Binärmusters mit einem Mikrocontroller LED schalten. Sprich eine 5 heißt dann für vier LED AUS EIN AUS EIN.

Nun wird jeder Port mit einem Byte angesteuert. Jedes Bit steht für einen einzelnen Pin:
PORTB = 0b10000000;
Heißt zum Beispiel, dass die achte LED an wäre, der Rest aus.

Jetzt habe ich z.B. die Zahl 25. Diese soll nicht als 11001 auf den Port, sondern ziffernweise als 0010 und 0101 -> 00100101.
Kann ich nun die beiden halben Bytes zusammensetzen oder wie ist es am sinnvollsten?

Ich könnte auch beide Ziffern nacheinander bitshiften und hintereinander in einen String schreiben. Aber wie bekomme ich die "00100101" dann zu 0b00100101?


Edit:
Ich wandel das ganze in eine künstliche Dezimalzahl um und schick diese ins Register:

int convertDezForRegister(int zahl){
  int z1 = zahl/10, z2 = zahl%10;
  return z1*16+z2;
}

So wird auch 25 die künstliche Dezimalzahl 37, die Binär 0010 0101 ist und somit meinem Muster entspricht face-smile