Forum: Mikrocontroller und Digitale Elektronik einzelne Prozessorpins per #define Ansprechen (ATmega16) AVR


von Daniela (Gast)


Lesenswert?

Hallo

Ich programmieren einen ATMega16 mit WinAVR. Am Port C habe ich 4 Status 
LED's angeschlossen. Diese kann ich mit z.B.
1
PORTC = PORTC |= (1<<PC4); // LED 1 an
2
PORTC = PORTC &= ~(1<<PC4); // LED 1 aus
ein- bzw. ausschalten.

Ich würde aber gerne
1
LED1 = AN;
2
LED1 = AUS;
schreiben.

Ich habe da schon eine ganze Zeit mit #define's rumprobiert, aber 
irgendwie bekomme ich es nicht hin.

Wie definiere ich einen einzelnen Pin von einem Port mit #define? Kann 
mir jemand bitte ein Beispiel zeigen?

von Falk B. (falk)


Lesenswert?

@ Daniela (Gast)

>Ich habe da schon eine ganze Zeit mit #define's rumprobiert, aber
>irgendwie bekomme ich es nicht hin.
1
#define LED1_AN  PORTC = PORTC |= (1<<PC4);
2
#define LED1_AUS PORTC = PORTC &= ~(1<<PC4); // LED 1 aus
3
4
LED1_AN
5
LED1_AUS

MG
Falk

von Daniela (Gast)


Lesenswert?

@Falk
Danke, aber ich habe wohl etwas undeutlich gefragt. Ich meine ein 
#define für AN bzw. AUS
1
#define AN 1
2
#define AUS 0
Ein zweites #define für den Prozessorpin (das ist mein Problem)
1
#define LED1 PORTC.PIN6
oder so ähnlich. Es funktioniert nur nicht.
Damit
1
LED1 = AN;
funktioniert. Oder geht das gar nicht?
Gruß
 Daniela

von Peter D. (peda)


Lesenswert?


von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Peter Dannegger wrote:
> http://www.mikrocontroller.net/attachment/27445/SBIT.C
>
>
> Peter

Wie effizient ist denn der Code den der Compiler daraus generiert im 
Gegensatz zu der xxx &=~_PV( ..... Lösung?

von yalu (Gast)


Lesenswert?

Genau gleich gut. In beiden Fällen erzeugt der Compiler daraus sbi- bzw- 
cbi-Instruktionen.

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Peter Dannegger wrote:
> http://www.mikrocontroller.net/attachment/27445/SBIT.C
>
>
> Peter

Und warum kann man statt:
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)

nicht auch:
typedef struct bits bits_t;
#define SBIT(port,pin) ( ((volatile bits_t)port).b##pin )

schreiben?

Viele Grüße!
Klaus

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

yalu wrote:
> Genau gleich gut. In beiden Fällen erzeugt der Compiler daraus sbi- bzw-
> cbi-Instruktionen.

Hm, dann spricht eigentlich nichts dagegen so eine Konstruktion zu 
verwenden, oder? Denn es macht den Code schon erheblich lesbarer finde 
ich.

Aber wie kommt es, dass man sowas in kaum einem Projekt sieht?


Viele Grüße!
Klaus

von Simon K. (simon) Benutzerseite


Lesenswert?

Klaus W. wrote:
> Aber wie kommt es, dass man sowas in kaum einem Projekt sieht?

Weil nicht jeder so denkt.

Ich finds einfach nur hässlich. Und wenn der zu kontrollierende Pin 
nicht konstant ist, gehts auch nicht. Also beispielsweise bei
1
PORTB = (1<<n);

Wenn wir schon dabei sind, bin ich überhaupt kein Fan von
1
typedef struct bits bits_t;

Man weiß im weiteren Verlauf nämlich nicht mehr ob bits_t nun ein Struct 
ist, oder ein "normaler" (per typedef festgelegter) Datentyp.

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Simon K. wrote:
> Klaus W. wrote:
>> Aber wie kommt es, dass man sowas in kaum einem Projekt sieht?
>
> Weil nicht jeder so denkt.
>
> Ich finds einfach nur hässlich. Und wenn der zu kontrollierende Pin
> nicht konstant ist, gehts auch nicht. Also beispielsweise bei
Das ist wahr...

>
1
> PORTB = (1<<n);
2
>

Allerdings stellt sich da dann nicht sowieso die Frage der Portabilität?
Wenn natürlich tatsächlich erst zur Laufzeit die Pinbelegung
festgelegt werden soll, hast Du völlig recht.

> Wenn wir schon dabei sind, bin ich überhaupt kein Fan von
Ok, das wiederum sieht man halt recht häufig!

>
1
> typedef struct bits bits_t;
2
>
>
> Man weiß im weiteren Verlauf nämlich nicht mehr ob bits_t nun ein Struct
> ist, oder ein "normaler" (per typedef festgelegter) Datentyp.
Da hast Du recht.

Und wo wir schon dabei sind:
Ich wäre ja auch geneigt die verwendeten Pins mit so "concat"-#defines 
zu definieren. So wie hier z.b.:

#define USB_CONCAT(a, b)            a ## b
#define USB_CONCAT_EXPANDED(a, b)   USB_CONCAT(a, b)
#define USB_OUTPORT(name)           USB_CONCAT(PORT, name)
#define USB_INPORT(name)            USB_CONCAT(PIN, name)
#define USB_DDRPORT(name)           USB_CONCAT(DDR, name)

Das scheint mir ganz praktisch, weil man nicht für jedes Signal
getrennt DDR und PORT bzw. PIN Register definieren muss.

Welche "Sünde" würde ich denn damit begehen?

(Abgesehen davon, dass dadurch natürlich auch allerlei "hardwired" wäre)

Viele Grüße!
Klaus

von yalu (Gast)


Lesenswert?

> Hm, dann spricht eigentlich nichts dagegen so eine Konstruktion zu
> verwenden, oder?

Eigentlich nicht.

> Aber wie kommt es, dass man sowas in kaum einem Projekt sieht?

In der 8051-Liga bieten die meisten Compiler eine Spracherweiterung,
die es erlaubt, einzelne Bits mit Namen anzureden. Da braucht man so
etwas nicht.

Die AVRler hatten zunächst nichts vergleichbares, einige wollten es
aber. Die obige Lösung entstand vor knapp einem Jahr hier im Forum in
einer Diskussion, ist also noch nicht so alt:

  Beitrag "sbit macro für avr-gcc"

Sie hat gegenüber der 8051-Lösung den Vorteil, dass sie nur
Standard-C-Sprachelemente verwendet. Sie setzt natürlich voraus, dass
der Compiler die Union-Zugriffe ähnlich optimiert wie die
Bitoperationen, was beim GCC das glücklicherweise zutrifft.

Die Lösung hat auch Einschränkungen: Man kann damit nur einzelne
Bits setzen oder Abfragen. Möchte man ganze Bitgruppen gemeinsam
behandlen, muss man wieder auf Bitoperationen zurückgreifen, die dann
noch kryptischer aussehen, weil man sie nicht mehr gewohnt ist ;-) Die
Fälle, wo man die Bitoperationen wirklich noch braucht, sind
allerdings relativ selten.

Die zweite Einschränkung hat Simon schon genannt: Variable Bitnummern
sind nicht möglich. Bei den 8051-Compilern geht m.W. so etwas wie
PORTB.n=1, wobei n eine Variable mit dem Wert [0..7] ist (kann mich
aber auch täuschen). Aber auch die variablen Bitnummern werden eher
selten benötigt (für Lauflichter, Multiplexer u.ä.).

von Oliver (Gast)


Lesenswert?

> Aber wie kommt es, dass man sowas in kaum einem Projekt sieht?

Weil ein einfaches
1
PORTC |= (1<<PC4);
(mit etwas Übung) genauso lesbar ist, wie
1
PORTC.4 = 1

Oliver

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Oliver wrote:
>> Aber wie kommt es, dass man sowas in kaum einem Projekt sieht?
>
> Weil ein einfaches
>
1
PORTC |= (1<<PC4);
> (mit etwas Übung) genauso lesbar ist, wie
>
1
PORTC.4 = 1

Hm, das stimmt im wesentlichen schon. Und es ist auch nicht so, dass ich 
mich dagegen sträuben würde, weil ich schreibfaul wäre oder so :-). Die 
Frage ist einfach: Welche Variante ist "besser". Also besser 
hinsichtlich der Wart- und Portierbarkeit. Wenn sie nebenbei leichter zu 
lesen ist, wäre das kein Schaden, aber ist sicher ein nachrangiges 
Kriterium.

Ausgangspunkt war folgende Problematik:
Ich habe gerade so ca. 2.5 AVR Projekte in C realisiert und bis jetzt 
meine Portpins mit simplen Makros definiert. z.B. so:
1
#define RFM_SIG_DDR  DDRB
2
#define RFM_SIG_PORT PORTB
3
#define RFM_SIG_PIN  PINB 
4
#define RFM_SCK      PB7
5
#define RFM_X        PB6
6
#define RFM_Y        PB5
...in der Hoffnung bei der Anpassung an einen anderen Prozessor oder ein 
anderes Leiterplattenlayout weniger Arbeit zu haben.
Nun sollte das Programm auf einen anderen Prozessor portiert werden, bei 
dem die Signale auf zwei verschiedene Ports verteilt sind.

Das geht so natürlich erstmal nicht.

Also viele Fußangeln, die man als Anfänger erstmal gar nicht erkennt. 
Die Frage ist, wie würde ein erfahrener Programmierer das lösen, einfach 
weil es sich im laufe der Zeit bewährt hat und später die wenigsten 
Schwierigkeiten zu erwarten sind.

Im Grunde hätte ich also für jedes Signal DDR, PORT, PIN und Bit 
definieren müssen. Das erscheint mir zunächst recht unhandlich. (Ich 
weiss, das ist jetzt nochmal eine andere Baustelle)
1
#define RFM_X_DDR    DDRB
2
#define RFM_X_PORT   PORTB
3
#define RFM_X_PIN    PINB 
4
#define RFM_X        PB7
5
#define RFM_Y_DDR    DDRB
6
#define RFM_Y_PORT   PORTB
7
.
8
.
Wenn ich nicht wirklich konsequent pro Signal 4 Konstanten definieren 
möchte muss ich mir an dieser Stelle auch schon überlegen ob es sich um 
einen Ein- oder Ausgang handelt.

Es scheint doch wesentlich übersichtlicher, wenn ich stattdessen die 
Signale einfach z.B. mit
1
#define RFM_X        PIN(B, 6)
definieren könnte und mir dann die eigentlichen Konstanten später im 
Programm über die weiter oben erwähnten Makros daraus "generiere".
z.B so:
1
SIGDDR( RFM_X ) &= ~( 1 << _PV(SIGBIT (RFM_X) );
2
SIGPORT( RFM_X ) |= ( 1 << _PV(SIGBIT (RFM_X) );

Wünschen würde man sich evtl. stattdessen ein einfaches
1
 RFM_X = 1;
schreiben zu können.

Würde man sich noch ein entsprechendes Makro definieren,
wäre ja sowas wie
1
 OUTBIT( RFM_X, <value> );
2
 i = INBIT( RFM_X );
zumindest möglich.

Also einen Signalnamen als kompaktes Objekt betrachten zu können, über 
dessen Bestandteile man sich beim Programmieren nicht mehr viel Gedanken 
machen muss.
Vielleicht bin ich da schon etwas objektorientierungsverseucht? Dabei 
habe ich ja eigentlich auch davon keine Ahnung :-).

Wenn man das mal etwas abstrakter sieht, ist es die Frage, ob man ein 
Hardwaresignal als unabhängiges Objekt betrachtet, oder einen Port als 
Objekt mit seinen Bitzuständen als Eigenschaften.
Je nach Anwendung ist vielleicht entweder das eine oder das andere näher 
an der Realität und besser zu handhaben.
Sehe ich ein Signal als Objekt, tue ich mich schwer wieder auf den Port 
als ganzes zuzugreifen (z.B. bei irgendwelchen Maskenoperationen). Sehe 
ich den Port als Objekt wird es schwierig, wenn der Hardwareport am 
Prozessor nicht mit der logischen Zuordnung zu einem realen 
Peripheriegerät übereinstimmt (also sich letztere z.B. über mehrere 
physikalische Ports erstreckt) und ich sowas portieren will.

Na, ich sehe schon, das wird jetzt alles doch recht philosophisch und 
ich sollte da erst nochmal drüber schlafen.

Viele Grüße!
Klaus

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Hallo!!!

Nachdem ich jetzt ein bischen mit dem Präprozessor gespielt habe, zeige 
ich jetzt mal, wie ich mir das ursprünglich vorgestellt hatte. Bzw. eine 
Lösung die dem am nächsten kommt.

Auch auf die Gefahr hin gesteinigt zu werden :-).

Wie sinnvoll das ganze nun wirklich ist, muss ich mir auch selbst 
erstmal noch überlegen.

Also:
1
struct bits {
2
   uint8_t b0:1;
3
   uint8_t b1:1;
4
   uint8_t b2:1;
5
   uint8_t b3:1;
6
   uint8_t b4:1;
7
   uint8_t b5:1;
8
   uint8_t b6:1;
9
   uint8_t b7:1;
10
} __attribute__((__packed__));
11
12
#define __SET_TO_IN(name, bit)     DDR##name &= ~(1<<bit)
13
#define __SET_TO_OUT(name, bit)    DDR##name |= (1<<bit)
14
#define __PORT(name, bit)   ((*(volatile struct bits*)&PORT##name).b##bit)
15
#define __PIN(name, bit)    ((*(volatile struct bits*)&PIN##name).b##bit)
16
#define SET_TO_IN(name)        __SET_TO_IN(name)
17
#define SET_TO_OUT(name)       __SET_TO_OUT(name)
18
#define PORT(name)             __PORT(name)
19
#define PIN(name)              __PIN(name)

Damit ist es nun möglich im Programm IO Signale wie folgt
zu definieren:
1
#define DEMO_CLOCK     A, 5
2
#define DATA_IN        A, 1
3
#define DATA_OUT       C, 3
4
#define SELECT         B, 5
5
#define TESTSIG        B, 5

Und schließlich kann man z.b. so darauf zugreifen:
1
   SET_TO_OUT( TESTSIG );
2
   PORT( TESTSIG ) = 1;
3
4
   SET_TO_IN( TESTSIG );
5
   i = PIN( TESTSIG );

Das Ergebnis wie erwartet:
1
   SET_TO_OUT( TESTSIG );
2
  62:   d5 9a           sbi     0x1a, 5 ; 26
3
   PORT( TESTSIG ) = 1;
4
  64:   dd 9a           sbi     0x1b, 5 ; 27
5
6
   SET_TO_IN( TESTSIG );
7
  66:   d5 98           cbi     0x1a, 5 ; 26
8
   i = PIN( TESTSIG );
9
  68:   80 e0           ldi     r24, 0x00       ; 0
10
  6a:   90 e0           ldi     r25, 0x00       ; 0
11
  6c:   cd 99           sbic    0x19, 5 ; 25

Ursprünglich war meine Hoffnung eine Lösung zu finden mit der man dann 
auch direkt auf das Signal z.B. mit
1
 
2
    TESTSIG=1;
3
    xyz=TESTSIG;
zugreifen kann.

Da sehe ich aber keine Möglichkeit, weil "TESTSIG=" und "=TESTSIG" dann 
vom Präprozessor unterschieden werden müsste. Im einen Fall müsste auf 
PORTx im anderen auf PINx zugegriffen werden. So wie ich das gcc manual 
verstehe, wird "TESTSIG" und "=" grundsätzlich in eigene Tokens 
aufgeteilt. Auch bei der Präprozessorbearbeitung.

Die Frage schließlich: Was bringt das ganze?

Vermutlich wenig.
Es ist mit weniger Schreibarbeit verbunden, aber ob es wirklich 
übersichtlicher wird, bin ich gar nicht sicher.

Natürlich ist es mit all den Nachteilen verbunden, die weiter oben schon 
angemerkt wurden.
Allerdings relativiert sich das meiner Meinung nach etwas:
Will man die Portierbarkeit des Codes auch für solche Fälle 
gewährleisten, dass Signalgruppen z.B. auch über Portgrenzen hinweg neu 
verteilbar sein sollen, muss sowieso jedes Signal für sich bearbeitet 
werden und ich kann nicht ganze Ports mit Bitmasken bearbeiten.
Für Fälle wo das einfach Schwachsinn wäre (ein 8-Bit Bus z.B.) ist die 
Vorgehensweise aber wohl einfach ungeeignet.

Vielleicht ist die beste Strategie wirklich einfach bei unabhängigen 
Signalen konsequent die vier "Bestimmungsstücke" PORTregister, 
PINregister, DDRregister und Bitnummer im Kopf zu definieren?
1
#define TESTSIG_DDR    DDRB
2
#define TESTSIG_PORT   PORTB
3
#define TESTSIG_PIN    PINB
4
#define TESTSIG        PB5

Hinsichtlich der Portabilität kommt das aufs gleiche raus.

Man könnte jetzt ja noch auf die Idee kommen sowas wie
1
#define TESTSIG        ( 1 << PB5 )
zu definieren.

Dann bräuchte man später nur noch:
1
TESTSIG_DDR &= ~TESTSIG;
schreiben.

Aber ob das nun wieder gut ist?


Viele Grüße!
Klaus

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Wieder ein paar neue Erkenntnisse:

Also im Einzelfall finde ich die Makrovariante schon erheblich leichter 
zu lesen. Wenn ich z.B. dasda:
1
     
2
        if ( ( ~KEY1_PIN & (1<<KEY1) ) & ( ~KEY2_PIN & (1<<KEY2) ) )
3
          PORT_LED1 |= ( 1<<LED1 );
4
        else
5
          PORT_LED1 &= ~( 1<<LED1 );

einfach als:
1
      PORT( LED1 ) = ~ ( PIN( KEY1 ) & PIN( KEY2 ) );

schreiben kann, finde ich das schon viel übersichtlicher.

Allerdings ist die zweite Variante um 28 Byte länger! Der Compiler baut 
da ziemlich wirres Zeug draus.

von yalu (Gast)


Lesenswert?

Bei mir sind's nur 22 Bytes Unterschied.

Die erste Variante tut aber wahrscheinlich nicht das, was du dir
vorstellst: Die If-Bedingung ist immer falsch, weswegen einiges
wegoptimiert wird. Richtig wird's, wenn du das mittlere & im if durch
&& ersetzt. Dann ist der Unterschied nur noch 14 Bytes.

Die zweite Variante schneidet deswegen schlechter ab, weil der
Compiler wegen der variablen Zuweisung an POET(LED1) keine
sbi/cbi-Instruktionen benutzt. Ein Kompromiss wäre
1
  if ( PIN( KEY1 ) && PIN( KEY2 ) )
2
    PORT( LED1 ) = 0;
3
  else
4
    PORT( LED1 ) = 1;

Sie ist so kurz wie die erste Variante, aber wenigstens ein kleines
Bisschen übersichtlicher.

PS: Deine beiden Varianten unterscheiden sich auch in Art und Weise,
wie die Eingangssignale negiert werden, was aber am grundsätzlichen
Inhalt des gerade Geschriebenen nichts ändert.

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

yalu wrote:
> Bei mir sind's nur 22 Bytes Unterschied.
>
> Die erste Variante tut aber wahrscheinlich nicht das, was du dir
> vorstellst: Die If-Bedingung ist immer falsch, weswegen einiges
> wegoptimiert wird. Richtig wird's, wenn du das mittlere & im if durch
> && ersetzt. Dann ist der Unterschied nur noch 14 Bytes.
Du verwirrst mich jetzt ein wenig. Natürlich hast Du recht! Aber ich 
hatte das wirklich getestet. Bei einigen Experimenten aber wohl die 
falsche Variante beim copy&paste erwischt.
Allerdings müsste doch ein || stehen, damit es äquivalent zur zweiten 
Schreibweise wird. Und dann sollte doch stattdessen auch | 
funktionieren.

> Die zweite Variante schneidet deswegen schlechter ab, weil der
> Compiler wegen der variablen Zuweisung an POET(LED1) keine
> sbi/cbi-Instruktionen benutzt. Ein Kompromiss wäre
Richtig.

> PS: Deine beiden Varianten unterscheiden sich auch in Art und Weise,
> wie die Eingangssignale negiert werden, was aber am grundsätzlichen
> Inhalt des gerade Geschriebenen nichts ändert.
Jein. Sie unterscheiden sich nicht nur in Art und Weise sondern auch in 
Sinn und Zweck. Was aber wie geschrieben ein Fehler ist :-).

viele Grüße!
Klaus

von Oliver (Gast)


Lesenswert?

>Nun sollte das Programm auf einen anderen Prozessor portiert werden, bei
>dem die Signale auf zwei verschiedene Ports verteilt sind.

Je nun, man sollte sich schon über seine eigenen Designentscheidungen im 
klaren sein. Und wenn du in deinem Programm voraussetzt, daß bestimmte 
I/O-Bits in aufsteigender Reihenfolge im gleichen I/O-Byte liegen 
sollen, dann erfordert eine Änderung an dieser Voraussetzung halt eine 
Änderung am Sourcecode. Hättest du von vornherein das Programm so 
ausgelegt, daß die Bits frei verteilt werden können, ginge die 
Portierung ohne Codeänderungen.

Aber das ist völlig unabhängig davon, ob du per Super-Macro nun Port2.1 
= 1:, oder einfach PORTC |= (1<<PC1); im Code stehen hast. Entscheidend 
ist allein, daß es im Falle der freien Portzuordnung zu jedem Portpin 
ein eigenes Define für den zugehörigen Port gibt.

Ob dann im Code
1
TESTSIG_BIT1_PORT.TESTSIG_BIT1 = 1;
oder
1
TESTSIG_BIT1_PORT |= (1<<TESTSIG_BIT1);
steht, ist völlig nebensächlich.


Oliver

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Oliver wrote:

> Je nun, man sollte sich schon über seine eigenen Designentscheidungen im
> klaren sein. Und wenn du in deinem Programm voraussetzt, daß bestimmte
Ganz klar! - Aber beim ersten Programm, bei dem man sich schon freut, 
wenn überhaupt der Programmer funktioniert, gibt's halt nicht viele 
Designentscheidungen :-). Aber man muss den gleichen Fehler ja nicht 
zweimal machen....

> Aber das ist völlig unabhängig davon, ob du per Super-Macro nun Port2.1
> = 1:, oder einfach PORTC |= (1<<PC1); im Code stehen hast. Entscheidend
> ist allein, daß es im Falle der freien Portzuordnung zu jedem Portpin
> ein eigenes Define für den zugehörigen Port gibt.
Grundsätzlich richtig!
Allerdings finde ich es relativ lästig, wenn ich bei 10 Signalen 40 
Zeilen pflegen muss, was im Falle der Macroverwendung eben nur 10 wären.

> Ob dann im Code
>
1
> TESTSIG_BIT1_PORT.TESTSIG_BIT1 = 1;
2
>
> oder
>
1
> TESTSIG_BIT1_PORT |= (1<<TESTSIG_BIT1);
2
>
> steht, ist völlig nebensächlich.
Ja, da würde ich Dir schon recht geben. Ich fände es immer noch 
praktischer einfach
1
TESTSIG=1;
schreiben zu können. Aber ich meine inzwischen schon auch dass die 
Nachteile bei dieser Variante überwiegen.

Viele Grüße!
Klaus

von yalu (Gast)


Lesenswert?

Klaus W. schrieb:
> Allerdings müsste doch ein || stehen, damit es äquivalent zur
> zweiten Schreibweise wird.

Ja.

> Und dann sollte doch stattdessen auch | funktionieren.

In diesem Fall würde das bitweise Oder zum gleichen Verhalten des
Programms führen. Ich würde aber aus zwei Gründen das logische Oder
|| dem bitweisen | vorziehen:

1. Das || drückt deine Absicht besser aus: Die Ausdrücke links und
   rechts davon bedeuten im Klartext "Taste1 ist gedrückt." bzw.
   "Taste2 ist gedrückt.". Beides sind Aussagen mit einem booleschen
   Wahrheitswert, nämlich true oder false. Boolesche Werte werden
   sinnvollerweise mit logischen Operation (also &&, || oder !)
   verknüpft. Die Bitoperatoren &, |, ^ und ~ hingegen rechnen mit
   Integeroperanden, weswegen sie meist für Maskierungsoperationen
   (wie in ~KEY1_PIN & (1<<KEY1)) eingesetzt werden.

2. Die ||-Variante ist 24 Bytes kürzer und sehr viel schneller.

Die logischen Operatoren && und || haben zudem den Vorteil, dass der
zweite Operand nur dann ausgewertet wird, wenn das Ergebnis nicht
schon nach Auswertung des ersten feststeht. Das kann insbesaondere
dann, wenn der zweite Operand ein komplizierter Ausdruck ist, einiges
an Zeit sparen.

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.