mikrocontroller.net

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


Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

uint32_t fehlendeDatensaetze;

uint8_t message_sequence_counter = message.data[0] & 0x1F;

// entsprechendes Bit löschen
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
 fehlendeDatensaetze &= ~(1UL << message_sequence_counter);


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

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super, danke so geht es.

Das war ja turbomäßig schnell.

Viele Grüße
Andreas

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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  :-)

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht 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:
fehlendeDatensaetze &= ~((uint32_t)1 << message_sequence_counter);

oder durch einen Suffix an der Konstanten:
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

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan P. (form)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.