Forum: Compiler & IDEs bits GELICHZEITIG setzen und löschen als Einzeiler?


von Axel R. (Gast)


Lesenswert?

Hallo zusammen,
ich == GCC-Anfänger :-))
ich habe ein Byte FLAGS.
Dort speichere ich allerhand Zustände. Nun möchte ich einige Bits
sezten und einige löschen.
Im GCC tutorial und in den entsprechenden Verweisen zur Bitmanipulation
werden immer mal ein oder meherere Bit gesetzt und mal welche gelöscht.

Habe ich auch verstanden.
Bits setzen:

#define BIT2 (2)
.
#define BIT5 (5)
.
.
.

FLAGS |= (1<<BIT5)|(BIT2)

Bits löschen:
FLAGS &= ~((1<<BIT5)|(1<<BIT2))
Soweit klar, muss man nur wissen und verstanden haben...

Wenn ich jetzt BIT5 und BIT1 setzen will UND BIT2 und BIT3 löschen,
(die restlichen sollen bleiben, wie sie sind) was mach ich denn dann??

FLAGS |= (1<<BIT5) | (1<<BIT1)
FLAGS &= ~((1<<BIT3) |(1<<BIT2)) würde gehen.

Das geht doch sicher auch irgentwie in einer Zeile, oder?

dankeschön

AxelR.

von Benedikt (Gast)


Lesenswert?

FLAGS = (FLAGS|(1<<BIT5) | (1<<BIT1))&(~((1<<BIT3) |(1<<BIT2)));

von Jan M. (mueschel)


Lesenswert?

So sollte das funktionieren:
FLAGS = (FLAGS | ((1<<BIT5) | (1<<BIT1)) & ~((1<<BIT3) |(1<<BIT2))
(Einfach klammern, wie in der Mathematik...)

Ich finde das allerdings deutlich weniger übersichtlich als die
"ausführliche" Variante. Im compilierten Code ergeben sich damit
sicher auch keine Vorteile.

von Axel R. (Gast)


Lesenswert?

Das ging schnell!! g

Ich probier mal, ob es mehr Code wird.
Die Übersichtlichkeit leidet wirklich - muss man zugeben.

Vielen Dank!
AxelR.

von Axel R. (Gast)


Lesenswert?

#define  GPRMC  (4)
#define  GPGGA  (5)
      case ('A'):            // The GPGGA sentence ID contains "A"
  //getrennte Umschaltung der Stati
  GPS_STATUS &= ~(1<<GPRMC);

  d0:  80 91 0a 02   lds  r24, 0x020A
  d4:  8f 7e         andi  r24, 0xEF  ; 239
  d6:  80 93 0a 02   sts  0x020A, r24

  GPS_STATUS |= (1<<GPGGA);

  da:  80 91 0a 02   lds  r24, 0x020A
  de:  80 62         ori  r24, 0x20  ; 32
  e0:  80 93 0a 02   sts  0x020A, r24

  // oder als Einzeiler
  GPS_STATUS = (GPS_STATUS|(1<<GPGGA) )&(~(1<<GPRMC));

  e4:  80 91 0a 02   lds  r24, 0x020A
  e8:  80 62         ori  r24, 0x20  ; 32
  ea:  8f 7e         andi  r24, 0xEF  ; 239
  ec:  80 93 0a 02   sts  0x020A, r24
        return;
  f0:  08 95         ret
    }

    return;

GPS_STATUS musste ich als 'volatile' deklarieren, sonst hat der
Compiler schlicht weg garnichts gemacht.
Das lerne ich noch...
Da ich eh nur zwei Datensatztypen (GGA+RMC) habe, könnte man auch mit
"^=" arbeiten.

Fazit:
Der Einzeiler ist (unwesentlich) kürzer, vielen Dank nochmals.

AxelR.

von Axel R. (Gast)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> GPS_STATUS musste ich als 'volatile' deklarieren, sonst hat der
> Compiler schlicht weg garnichts gemacht.

Dann hast du das Ergebnis wohl nicht weiter benutzt.

von Werner A. (Gast)


Lesenswert?

Wenn es um das gleichzeitig setzen und löschen geht, könntest Du ja auch
mit einer Hilfsvariable arbeiten und zunächst da alles machen und dann
zurückschreiben.
1
temp = flag;
2
temp |= (1<<BIT5) | (1<<BIT1)
3
temp &= ~((1<<BIT3) |(1<<BIT2))
4
flag = temp;

von Axel R. (Gast)


Lesenswert?

@Werner
naja, soo gleichzeitig muss es nicht... trotzdem Danke!
@Jörg
Ja, ich hatte die Variable noch nicht "in Verwendung". Das stimmt
wohl - so weit war ich da noch nicht. In der Hauptschleife frage ich
nach, ob beide GPS-Datensätze vorliegen, um diese dann verarbeiten zu
können.
Da es nur zwei sind ($GGA und $RMC), waren da noch Bits in der Variable
"GPS_STAUS" frei. Es gibt im Programm zwar eine Variable namens
"sentence_type". Aber die wollte ich sparen und statt dessen BIT 5
und 6 oderso von "GPS_STAUS" mit heranziehen.

Ich werde mir mal die Bitfields (hiess doch so?) ansehen. Damit gehts
vielleicht einfacher. Men "IF" Konstrukt in der Main sieht toll aus!
Passt (fast) garnicht in eine Zeile
if (((GPS_STATUS & (1<<RMC_OK)) == (1<<RMC_OK)) && ((GPS_STATUS &
(1<<GGA_OK))== (1<<GGA_OK)))

Wenn da jemand eine Idee hat... Sollte aber so den Regeln entsprechen.
rmc_ok und gga_ok sind per define festgelegt
#define GGA_OK    (2)
#define RMC_OK    (3)

Bin noch am lernen. sprintf für Debugausgaben ist ja wohl der Hammer!
Da platzt mein kleiner Mega48 ja sofort aus allen Nähten :-(( schmoll

Dabei wollte ich unterwegs nur Grad, Minuten und sekunden
(Länge/Breite) in eine ganzzahl wandeln und mit der von Zuhause
vergleichen. Das kann ich mir wohl in "C" und mit dem Mega48
abschminken - schade...


Viele Grüße, schönen Dank

AxelR.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das geht kompakter:

   if (((GPS_STATUS & (1<<RMC_OK)) == (1<<RMC_OK)) && ((GPS_STATUS &
   (1<<GGA_OK))== (1<<GGA_OK)))

kann auch als

   if ((GPS_STATUS & (1<<RMC_OK)) && (GPS_STATUS & (1<<GGA_OK)))

geschrieben werden. Da in beiden Teilausdrücken GPS_STATUS mit nur
einem Bit verANDet wird, genügt es, auf != 0 abzufragen.

Das macht das doch schon ein bisschen lesbarer, oder?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Ja, ich hatte die Variable noch nicht "in Verwendung".

Dann ist der Compiler wirklich eifrig im Wegoptimieren.  volatile kann
dagegen helfen, man sollte nur dran denken, es wieder rauszuwerfen,
wenn der Code fertig ist.

> Ich werde mir mal die Bitfields (hiess doch so?) ansehen. Damit
> gehts vielleicht einfacher.

Ja, für derartige Flags nehme ich gern mal bit fields.

> Bin noch am lernen. sprintf für Debugausgaben ist ja wohl der
> Hammer!  Da platzt mein kleiner Mega48 ja sofort aus allen Nähten
> :-((

Debuggen sollte man auch nicht auf einem ATmega48.  Fürs Debuggen kann
man nie genug Ressourcen frei haben.  Nimm einen ATmega168, der ist
pin- und funktionskompatibel bei deutlich mehr Speicher.

printf() ist halt vom Prinzip her riesig, da die Entscheidung, was von
den Möglichkeiten wirklich benötigt wird, erst zur Laufzeit feststeht.

> Dabei wollte ich unterwegs nur Grad, Minuten und sekunden
> (Länge/Breite) in eine ganzzahl wandeln und mit der von Zuhause
> vergleichen. Das kann ich mir wohl in "C" und mit dem Mega48
> abschminken - schade...

Oder halt mit itoa() arbeiten, da hast du eben nur keine netten Dinge
wir Vornullen etc.

von AxelR. (Gast)


Lesenswert?

Wenn es reicht, auf !=0 abzufragen, dann könnte man ja auch eine weitere
Definition einführen, wo beide (RMC_OK und GGA_OK) enthalten sind. Dann
allerdings nicht mehr auf !=0 abfragen, sondern auf die Summe beider.
#define GSP_OK (12) //BIT2 und BIT3 zusammen
if ((GPS_STATUS & GPS_OK) == GPS_OK) müsste ja gehen, oder?

Naja - macht jedenfall Spaß.
Obwohl ich besser und schneller kleine Leiterplatten entwerfen kann.
Vlt.kann ich da ja mal jemanden helfen - würde mich freuen!
man kann eben nicht alles können :-))

Ich habe im Makefile jetzt erstmal die minimalistische Printf Variante
eingestellt.
Das brachte nochmal 1K einsparung. Ich könnte die Daten aber auch auf
PORTB ohne Printf ausgeben...

Jetzt werd ich erstmal einen Mega168(wiedermal nur im MLF)
"anfassbar" machen. Habe i.M. keinen anderen zur Hand.

VlG
AxelR.

von Dirk (Gast)


Lesenswert?

Hi,

du koenntest auch die Output Funktionen von Peter Danneger aus der
Codesammlumng nehmen. Der Code von PeDa ist fuer C51, aber ich hatte
sie damals auf GCC portiert.

Der Code braucht 900 Byte fuer String, hex, Dezi, Float usw.

Gruß,
Dirk

von AxelR. (Gast)


Lesenswert?

..Output Funktionen..Codesammlumng..Peter Danneger

finde ich nicht!
ich habe nach "C51", "Output", "PeDa", "float", "printf" usw.
in der Codesammlung gesucht :-(( määäh

von D. H. (slyd)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

> Das geht kompakter:
>
>    if (((GPS_STATUS & (1<<RMC_OK)) == (1<<RMC_OK)) && ((GPS_STATUS &
>    (1<<GGA_OK))== (1<<GGA_OK)))
>
> kann auch als
>
>  if ((GPS_STATUS & (1<<RMC_OK)) && (GPS_STATUS & (1<<GGA_OK)))

Oder noch ne Variante:
Wenn man Schreibarbeit sparen möchte, kann man sich oft mit einem
Makro helfen (auch wenn ich nicht so ein Fan von Makros bin, na ja
von C++ halt 'verdorben' )


#define BIT_SET( Where, What ) ( Where & (1<<What) == (1<<What) )

Dann schreibst du

   if( BIT_SET( GPS_STATUS, RMC_OK ) &&
       BIT_SET( GPS_STATUS, GCA_OK ) )

Wobei ich sagen muss, dass ich solche && oder || verknüpfte
logische Ausdrücke überhaupt gerne auf 2 Zeilen aufteile.

von AxelR. (Gast)


Lesenswert?

@Dominik
gefunden und kopiert - Danke! Probier ich heute abend aus.
@Karl-Heinz
Makros? intesessant... und hier mal einleuchtend (habe da aber auch
schon ganz übelst komplizierte Sachen gesehen)

Man kann doch nicht einfach so eine neue Zeile anfangen?
Nun, offensichtich doch -

Mega168 im MLF nach elm-chang (kopfüber mit doppeltape auf lochraster)
adaptiert (schwitz) gg

Schönen Gruß

AxelR.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Warum so umständlich?

  #define BIT_SET( Where, What ) ( Where & (1<<What) == (1<<What) )

Den Vergleich kann man sich hierbei schenken

  #define BIT_SET( Where, What ) ( Where & (1<<What))

da nur ein Bit abgefragt wird.

Ein blöder Compiler macht daraus womöglich einen richtigen Vergleich,
statt einfach auf 0 bzw. Nichtnull zu testen.

Ich würde allerdings bei der Namenswahl auch noch etwas länger
nachdenken, es geht ja nicht darum, ein Bit zu setzen, sondern um zu
testen, ob es gesetzt ist. Das nur am Vertauschen von "bit" und
"set" festzumachen ...

von AxelR. (Gast)


Lesenswert?

BIT_IS_SET klingt gut.
C macht Spass (FatsAVR war aber einfacher [auweia- bin schon weg]) -
ich muss aber weiterabreiten, bis denne

AxelR.

von Rolf Magnus (Gast)


Lesenswert?

C++ ist sogar noch viel cooler.

von Karl heinz B. (kbucheg)


Lesenswert?

> Warum so umständlich?

:-)

Weil es immer wieder Programmierer gibt, die sich in den
Fuss schiessen.
Im Ernst. Ich hab vor Jahren den Vergleich mal weggelassen.
Prompt hat ein Kollege das hier gebaut (sinngemaess):


  int NrBitsSet = BIT_SET( PORTA, 2 ) +
                  BIT_SET( PORTA, 3 ) +
                  BIT_SET( PORTA, 4 );

  if( NrBitsSet > 1 )  // wenn mindestens 2 von 3 gesetzt sind

> BIT_IS_SET klingt gut

Meist zieht man das IS vor:

  IS_BIT_SET

Alle Dinge die mit 'IS' beginnen sind 'Prädikate' (liefern
also eine Ja/Nein Aussage). Ist aber nur so eine Konvention.

> C++ ist sogar noch viel cooler.

Da steh ich voll drauf :-)

von Karl heinz B. (kbucheg)


Lesenswert?

> Man kann doch nicht einfach so eine neue Zeile anfangen?
> Nun, offensichtich doch -

Klar kann man.
Wenn dein Compiler deinen Source Code in die Finger
kriegt (nach dem Präprozessor), dann ist das erste
was er macht: Er ersetzt den sog. 'Whitespace' durch
genau ein Leerzeichen. Whitespace sind Sequenzen, die
nur aus Leerzeichen, Tabulatoren, Zeilentrenner bestehen.
Oh. Vorher werden, glaub ich, noch Kommentare durch ein Leerzeichen
ersetzt.

d.h. Dein Compiler macht aus dem hier

   int i;
   int j;
   for( i = 0; i < 8; ++i )
     j = 5;

das hier:

  int i; int j; for( i = 0; i < 8; ++i ) j = 5;

Gibt auch keinen Grund das nicht zu tun. Der Compiler
wird durch die C Grammatik udnd die ';' geleitet
und nicht durch die Zeilentrenner.

Fortran ist da noch konsequenter: Alle Leerzeichen (natuerlich
nicht in Strings) werden entfernt bevor die Anweisung
übersetzt wird.
d.h. man kann in Fortran auch so schreiben:

      I N T E G E R * 4   ALPHA
      R E A L * 8         BETA

      BETA = A L P H A  *  2

man kann aber auch so schreiben :-)

      INTEGER*4ALPHA
      REAL*8BETA
      BETA=ALPHA*2

von Karl heinz B. (kbucheg)


Lesenswert?

> das hier:
>
>  int i; int j; for( i = 0; i < 8; ++i ) j = 5;

Na ja. Er macht es nicht wirklich. Aber er tut so als ob.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dazu fällt mir nur noch ein:

Real programmers can program FORTRAN in any language.

:-)

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.