Hallo, habe folgendes Problem: uint32_t zahl = 2863311530; Ich möchte die Variable zahl Bit für Bit untersuchen, ob das jeweilige Bit eine 0 oder eine 1 ist. Wahrscheinlich geht das mit einer "Bitschieberoperation" ganz einfach. Man schiebt einfach die Zahl "1 hoch Bitstelle" mit einer UND-Verknüpfung über die Bits 0 bis 31 und erhält für jede Bit-Stelle eine 0 oder 1 als Ergebnis. So weit, so gut, aber wie wird das in der Praxis geschrieben? for (i = 0; i< 33; i++) { b = (Zahl & (2 hoch i)); ergebnis_verwursten (uint_t b); } Es gibt ja die Befehle << und >>, damit geht es sicher eleganter, zumal in C ja kein Potenzoperator ohne weiteres zur Verfügung steht. (gibt es den Variablentyp uint1_t eigentlich?) Viele Grüße und auf jeden Fall schon mal Danke fürs Lesen!
Hallo fragendermensch, ich würde nur das Bit 0 der Zahl testen:
1 | if ( Zahl & (1ul<<0) ) { .. } |
und dann die Zahl nach rechts Schieben
1 | zahl = zahl >> 1ul; // lange Schreibweise |
2 | // oder
|
3 | zahl >>= 1ul; |
4 | // oder
|
5 | zahl = zahl / 2; |
6 | // oder
|
7 | zahl /= 2; |
Mehr steht wie immer in dem C Buch: http://de.wikipedia.org/wiki/The_C_Programming_Language
fragendermensch schrieb: > > for (i = 0; i< 33; i++) > { > b = (Zahl & (2 hoch i)); > > ergebnis_verwursten (uint_t b); > } > > > > Es gibt ja die Befehle << und >>, damit geht es sicher eleganter, zumal > in C ja kein Potenzoperator ohne weiteres zur Verfügung steht. 1 << i IST die Operation '2 hoch i' 2 hoch 0 -> 1 1 << 0 -> 1 2 hoch 1 -> 2 1 << 1 -> 2 2 hoch 2 -> 4 1 << 2 -> 4 2 hoch 3 -> 8 1 << 3 -> 8 2 hoch 4 -> 16 1 << 4 -> 16 ... Aber eigentlich will man auf einem AVR die Operation '1 << i' nicht machen, weil dem AVR die dazu notwendige Hardware-Ausstattung fehlt. Daher macht man was anderes: Wenn der Berg nicht zum Propheten kommt, dann muss eben der Prophet zum Berg. Einigen wir uns auf das unterste Bit einer Zahl. Dieses Bit kann man leicht extrahieren :-) x & 0x01 soweit so gut. Was bringt das? Nun ganz einfach, nachdem dieses Bit verwurschtet wurde, schiebt man einfach die Zahl x um eine binäre Stelle nach RECHTS, so dass jetzt das ursprüngliche Bit 1 an die unterste STelle kommt, wo man es mit dem & wieder leicht extrahieren kann. Und dann schiebt man x wieder um 1 Stelle nach rechts, wodurch das ursprüngliche Bit 2 an die unterste Stelle zu liegen kommt. etc. etc. for( i = 0; i < 32; i++ ) { mach was mit ( x & 0x01 ); x >>= 1; } das ist nur eine Möglichkeit! Es gibt noch viele andere. Zb kann man ja auch anstelle des untersten Bit das oberste nehmen und da dann sukzessive alle Bits von x durch linksschieben an dieser Position 'vorbeischleusen'. Oder man schiebt sukzessive eine 1 in einem Maskenbyte von einer Stelle zur nächsten durch, mit der man dann mittels eines & sich das interessierende Bit aus dem x herausholt, oder ....
Danke an euch beide für die schnellen Antworten! Karl Heinz Buchegger schrieb: > for( i = 0; i < 32; i++ ) > { > mach was mit ( x & 0x01 ); > x >>= 1; > } Nach rechts schieben bedeutet, die Zahl wie auf einem Karussell um eine Stelle zu drehen, dass das LSB plötzlich das MSB ist und dass das zweitkleinste Bit der Zahl nun das LSB ist, nehme ich an. Ok, dann werde ich das morgen mal im Programm ausprobieren. Habt noch mal vielen Dank für die Hilfe!!!
fragendermensch schrieb: > Danke an euch beide für die schnellen Antworten! > > Karl Heinz Buchegger schrieb: >> for( i = 0; i < 32; i++ ) >> { >> mach was mit ( x & 0x01 ); >> x >>= 1; >> } > > Nach rechts schieben bedeutet, die Zahl wie auf einem Karussell um eine > Stelle zu drehen, dass das LSB plötzlich das MSB ist und dass das > zweitkleinste Bit der Zahl nun das LSB ist, nehme ich an. Nein. Was rechts rausfällt, ist weg. Was du meinst trägt den Terminus 'rotieren' und diese Operation gibt es zwar auf Assemblerebene aber nicht auf C-Ebene.
fragendermensch schrieb: >> x >>= 1; PS: x <<= 7; würde die Zahl x um 7 binäre Stellen nach links verschieben, stimmts?
fragendermensch schrieb: > fragendermensch schrieb: >>> x >>= 1; > > PS: > > x <<= 7; > > würde die Zahl x um 7 binäre Stellen nach links verschieben, stimmts? Alle C-Operationen, die nach dem Muster x op= y aufgebaut sind, sind eine Kurzschreibweise für x = x op (y) d.h. x <<= 2 ist eine Kurzschreibweise für x = x << 2 und x << 2 wiederrum, ist die C-Schreibweise für nimm x schiebe das Bitmuster nach links (weil die 'Haken' nach links zeigen) und zwar um 2 Stellen d.h. die Operation <<= macht genau diese Operation und weist dann das Ergebnis davon wieder der Variablen links vom = zu. Letzters in völliger Analogie zu beispielweise a *= 5 welches eine Kurzschreibweise für a = a * 5 ist, deren Operation selbsterklärend sein sollte und nach genau demselben Muster abläuft. Nur eben mit einer Multiplikation * anstelle einer Schiebeoperation << (links schieben) bzw. >> (rechts schieben). D.h. ja x <<= 7 verschiebt im Endeffekt das Bitmuster von x um 7 Stellen nach links, wobei von rechts mit 0-Bits aufgefüllt wird.
PPS: dann kann man wahrscheinlich auch folgendes machen!??: y = ( x <<= 3 );
Danke für die superausführliche Erklärung! Meine letzte Frage hatte sich mit deinem letzten Posting überschnitten, jetzt ist es klar! Noch mal Danke!!!
fragendermensch schrieb: > PPS: > > dann kann man wahrscheinlich auch folgendes machen!??: > > y = ( x <<= 3 ); :-) Natürlich. In C ist auch eine Zuweisung ein 'arithmetischer Ausdruck', der ein Ergebnis hat. Wenn a = b = 5; genau aus diesem Grund zulässig ist, dann ist es selbstverständlich auch y = x <<= 3; Du scheinst irgendwie der Vorstellung verhaftet zu sein, dass << bzw. >> irgendwie aussergeöhnlich wären. Das sind sie nicht. Das sind ganz normale 'arithmetische Operationen, wie zb + - * / % es auch sind. Die Operationen verknüpfen 2 Operanden anhand einer Vorschrift und liefern ein Ergebnis. Bei '*' ist eben die Verknüpfungsvorschrift für a*b dergestalt, dass das Ergebnis die Multiplikation von a mit b darstellt. Und bei a << b ist die Verknüpfungsvorschrift der Operanden dergestalt, dass das Ergebnis aus a um b Stellen binär nach links verschoben entsteht. Auch == ist nichts anderes als eine derartige Operation. Das Verknüpfungsergebnis von a == b ist eine 1, wenn der Vergleich zutrifft und ist 0, wenn er nicht zutrifft. Aber abgesehen davon, dass du so etwas wahrscheinlich noch nie als 'arithmetische Operation im Sinne von + - * /' angesehen haben dürftest, gibt es in C da keinen prinzipiellen Unterschied! Es ist ein Operator (genauso wie != < > <= >=) der einen linken Operanden mit einem rechten Operanden anhand einer vorschrift miteinander verknüpft und anhand dieser Vorschrift ein Ergebnis erzeugt. Was auch immer dann mit diesem Ergebnis weiter passiert liegt ausserhalb der Kontrolle des Operators und ist auch nicht sein Bier. D.h. es ist möglich zu schreiben d = ( c = ( a == b ) * 5 ) << 3; und dieser Ausdruck hat einen exakt definierten Ablauf.
Karl Heinz Buchegger schrieb: > d = ( c = ( a == b ) * 5 ) << 3; > > und dieser Ausdruck hat einen exakt definierten Ablauf. Das ist mir grade ein bisschen hoch, aber Danke für die Erklärung! C ist wirklich enorm vielseitig, wie mir scheint. Habe noch eine andere Frage zu Variablen: Habe hier ein Programm-Listing für Arduino, wie es scheint. Dort werden folgende Variablen deklariert: unsigned char x; double y; long int z; Können diese Variabeltypen beim Programmieren mit dem AVR-Studio so einfach übernommen werden oder muss man etwas besonderes beachten? "unsigned char x" kann man sicher einfach als "uint8_t x" ausdrücken, aber bei den anderen bin ich mir nicht sicher, zumal verschiedene Quellen unterschiedliche Angaben dazu machen, was "double" und "long int" sind.
fragendermensch schrieb: > Karl Heinz Buchegger schrieb: >> d = ( c = ( a == b ) * 5 ) << 3; >> >> und dieser Ausdruck hat einen exakt definierten Ablauf. > > Das ist mir grade ein bisschen hoch, :-) macht nix. Wer sowas schreibt, sollte sowieso mit dem nassen Fetzen verjagt werden. > Habe noch eine andere Frage zu Variablen: > > Habe hier ein Programm-Listing für Arduino, wie es scheint. > > Dort werden folgende Variablen deklariert: > > unsigned char x; > double y; > long int z; > > Können diese Variabeltypen beim Programmieren mit dem AVR-Studio so > einfach übernommen werden oder muss man etwas besonderes beachten? sind alles C STandard Datentypen, die jeder C Compiler kennen muss. > > "unsigned char x" kann man sicher einfach als "uint8_t x" ausdrücken, ja. > aber bei den anderen bin ich mir nicht sicher, zumal verschiedene > Quellen unterschiedliche Angaben dazu machen, was "double" und "long > int" sind. long ist auf einem AVR ein int32_t (also ein 32 Bit Integer mit Vorzeichen) double ist beim gcc auf einem AVR dasselbe wie ein float: Ein Floating Point Wert mit 4 Bytes. Mach auf einem AVR lieber einen Bogen um die Standard-Datentypen. Die AVRs sind zu klein, als das du dir da Überraschungen einhandeln willst. Lieber explizit sein uint8_t unsigned char int8_t signed char char char int16_t int uint16_t unsigned int int32_t long uint32_t unsigned long float float double float Einen 'echten' double gibt es beim gcc nicht. double und float sind beides float. gib im Speziellen darauf acht, ob der Datentyp int SINNVOLL benutzt wird. Oft ist es so, dass ein int benutzt wird, wo es ein uint8_t auch tut, weil die Zahlen niemals so groß werden, dass 8 Bit nicht reichen. 8-Bit Arithmetik ist aber für den AVR einfacher als 16 Bit Arithmetik!
Karl Heinz Buchegger schrieb: > Mach auf einem AVR lieber einen Bogen um die Standard-Datentypen. Die > AVRs sind zu klein, als das du dir da Überraschungen einhandeln willst. > Lieber explizit sein > > uint8_t unsigned char > int8_t signed char > char char > int16_t int > uint16_t unsigned int > int32_t long > uint32_t unsigned long > > float float > double float > > Einen 'echten' double gibt es beim gcc nicht. double und float sind > beides float. Danke für die Infos, habe es direkt notiert. Werde es gleich ausprobieren. Der betreffende Programmteil funktioniert zwar bei höheren Zahlen anscheinend richtig, beim Input kleinerer Zahlen wird aber plötzlich alles Null im Output, daher vermute ich ein Problem bei den Variabeltypen...
So, mit den neuen Variabel-Typen funktioniert es jetzt! Noch mal Danke!!! Gibt es eigentlich einen Befehl, der die Bits einer Variablen spiegeln kann (also so, dass das LSB zum MSB wird und umgekehrt)?
Karl Heinz Buchegger schrieb: > Aber eigentlich will man auf einem AVR die Operation '1 << i' nicht > machen, weil dem AVR die dazu notwendige Hardware-Ausstattung fehlt. Weil dem AVR der Befehl shift-left fehlt?
Nein, der Shift-Left-Befehl ist vorhanden. Aber der AVR hat keinen Barrelshifter, sodass Shifts um mehr als eine Stelle ziemlich unhandlich werden. Gruß Marius
fragendermensch schrieb: > Gibt es eigentlich einen Befehl, der die Bits einer Variablen spiegeln > kann (also so, dass das LSB zum MSB wird und umgekehrt)? könnte man für sowas und ähnliche allgemeine probleme (z.b. variable in string umwandeln) eine Hilfsdatei schreiben und im AVR-Studio einbinden? dann hätten alle was davon
flo schrieb: > fragendermensch schrieb: >> Gibt es eigentlich einen Befehl, der die Bits einer Variablen spiegeln >> kann (also so, dass das LSB zum MSB wird und umgekehrt)? > > könnte man für sowas und ähnliche allgemeine probleme (z.b. variable in > string umwandeln) eine Hilfsdatei schreiben und im AVR-Studio einbinden? > > dann hätten alle was davon Ähm. Es hätten auch alle was davon, wenn die Neulinge sich ein C-Buch kaufen würden, es durcharbeiten und dann zumindest einen groben Überblick haben würden, welche Operatoren es gibt und welche vorgefertigten Funktionen sie bereits zur Verfügung haben. > (z.b. variable in string umwandeln) Was stört dich an itoa utoa ltoa ultoa ftoa sprintf
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.