Forum: Compiler & IDEs 32-Bit Variable lässt sich nicht löschen


von Andreas (Gast)


Lesenswert?

Hallo,

ich habe eine 32-Bitvariable in der ich mir die Anzahl von zu 
empfangenden Datensätze speichere. Für jeden Datensatz wird ein Bit 
gesetzt. Beim Empfang wird das entsprechende Bit über eine andere 
Variable gelöscht.

1
uint32_t fehlendeDatensaetze;
2
3
uint8_t message_sequence_counter = message.data[0] & 0x1F;
4
5
// entsprechendes Bit löschen
6
fehlendeDatensaetze &= ~(1 << message_sequence_counter);


Ich habe mir die Variablen über die serielle Schnittstelle ausgeben 
lassen.
Das Setzen der einzelnen Bits funktioniert. Auch das Löschen. Allerdings 
nur bis message_sequence_counter = 14 ist. Nach dem Löschen wird noch 
ordnungsgemäß fehlendeDatensaetze der Wert 1f8000 angezeigt. Sobald wie 
jetzt aber message_sequence_counter = 15 ist und das bitweise löschen 
erfolgt ist danach der gesamte Wert 0. Es sollte aber dann 1f0000 sein.

Ich kann keinen counter nehmen und einfach runterzählen. Es muss 
sichergestellt sein, dass doppelt ankommende Datensätze nur einmal 
verwertet werden.

Ich habe den Eindruck als liegt es am "<<". Einen Fehler in meiner 
Software will ich nicht ausschliessen sehe ich derzeit aber nicht.

Kann mir hier jemand einen Tipp geben woran es liegt?

Danke
Andreas

von Karl H. (kbuchegg)


Lesenswert?

Andreas schrieb:

> // entsprechendes Bit löschen
> fehlendeDatensaetze &= ~(1 << message_sequence_counter);


Diese 1 hier ist erst mal vom Datentyp int. D.h. bei dir hat sie 16 Bit.
Sobald du diese 1 16 mal nach links verschoben hast, ist das 1 Bit links 
rausgefallen und es bleibt nur noch 0 übrig.
1
 fehlendeDatensaetze &= ~(1UL << message_sequence_counter);


> Kann mir hier jemand einen Tipp geben woran es liegt?
Süffisant gesagt:
an fehlenden C Kentnissen

von Andreas (Gast)


Lesenswert?

Super, danke so geht es.

Das war ja turbomäßig schnell.

Viele Grüße
Andreas

von Andreas (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Süffisant gesagt:
> an fehlenden C Kentnissen

O.K. hatte ich erst übersehen. Ich war so begeistert von der schnellen 
Antwort, dass ich es direkt ausprobieren musste.

Werde ich mir merken und die Kenntnisse versuchen zu verbessern  :-)

von Andreas F. (aferber)


Lesenswert?

Andreas schrieb:
> fehlendeDatensaetze &= ~(1 << message_sequence_counter);

"1" als Konstante hat bei C immer den Typ "int", der bei dir offenbar 16 
Bit hat, wovon eines das Sign-Bit ist. Die Berechnung der Bitmaske 
erfolgt komplett mit dem Typ "int", deshalb kommt es ab 15 für 
message_sequence_counter zu undefiniertem Verhalten.

Um den Compiler zu zwingen, einen anderen Datentyp zu verwenden, musst 
du der Konstanten den entsprechenden Typ verpassen, entweder über Cast:
1
fehlendeDatensaetze &= ~((uint32_t)1 << message_sequence_counter);

oder durch einen Suffix an der Konstanten:
1
fehlendeDatensaetze &= ~(1UL << message_sequence_counter);

Welchen der Wege du wählst bleibt deinem Gusto überlassen.

Was du noch vielleicht noch wissen solltest: ein Shift um einen 
variablen Wert kann z.B. bei AVR eine ziemlich teure Operation werden, 
insbesondere mit 32Bit-Werten wie hier. Im Extremfall (bei 
message_sequence_counter=31) braucht der Shift auf AVR mehr als 200 
Takte! Wenn es also eng wird mit der Rechenleistung, dann kann sowas im 
C-Code harmlos aussehendes durchaus zum Problem werden.

Andreas

von Andreas (Gast)


Lesenswert?

Andreas Ferber schrieb:
> Was du noch vielleicht noch wissen solltest: ein Shift um einen
> variablen Wert kann z.B. bei AVR eine ziemlich teure Operation werden,
> insbesondere mit 32Bit-Werten wie hier.

Danke. Werde ich im Hinterkopf behalten. Könnte ein Problem werden wenn 
die Datensätze kurz hintereinander gesendet werden. In der Regel wird es 
aber nur vorkommen, dass die Nutzdaten aus max. 4 einzelnen Datensätzen 
bestehen.

Auch für den Rest danke.
Mir war nicht bewusst, dass "1 <<" hierbei etwas mit int erzeugt wird. 
Ich hatte (fälschlicherweise) angenommen es wird ein Speicher in 
derselben Größe wie auf der linken Seite der Zuweisung (in meinem Fall 
unint32_t) vom Compiler erzeugt.

Ihr habt mir sehr weitergeholfen

Andreas

von Karl H. (kbuchegg)


Lesenswert?

Andreas schrieb:

> Mir war nicht bewusst, dass "1 <<" hierbei etwas mit int erzeugt wird.
> Ich hatte (fälschlicherweise) angenommen es wird ein Speicher in
> derselben Größe wie auf der linken Seite der Zuweisung (in meinem Fall
> unint32_t) vom Compiler erzeugt.

Das wird es NIEMALS.

Wie und in welchen Datentypen eine Operation (hier das <<) abläuft, 
hängt NIEMALS davon ab, was mit dem Ergebnis gemacht wird. Es sind immer 
nur die Datentypen der beteiligten Operanden, die das entscheiden. In 
diesem konkreten Fall mit Schiebeoperationen ist es sogar nur der 
Datentyp, der links vom << steht. Also der 1. Und der ist int.

von Stefan P. (form)


Lesenswert?

Gut das ihr darüber geredet habt.
Ich hatte momentan das exakt selbe Problem und bin irgendwie aus Zufall 
über diesen Thread gestolpert.

Danke.

von Andreas (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Das wird es NIEMALS.
>
> Wie und in welchen Datentypen eine Operation (hier das <<) abläuft,
> hängt NIEMALS davon ab, was mit dem Ergebnis gemacht wird. Es sind immer
> nur die Datentypen der beteiligten Operanden, die das entscheiden. In
> diesem konkreten Fall mit Schiebeoperationen ist es sogar nur der
> Datentyp, der links vom << steht. Also der 1. Und der ist int.

Eigentlich hätte ich es mir denken können/müssen. Wenn ich einem int ein 
float zuweise wird auch nur der ganzzahlige Anteil genommen.

Es lag wohl eher daran, dass ich nicht wusste was (1 << var) genau macht 
und ich angenommen hatte es wird automatisch über 16 Bit hinausgehen 
weil "var" die Anzahl vorgibt.

Ohne Eure Hilfe wäre ich aber nie darauf gekommen 1UL zu nehmen.

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
Noch kein Account? Hier anmelden.