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!
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:> 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.
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