Forum: Compiler & IDEs if(a) oder besser if(a == 1)


von Skittler (Gast)


Lesenswert?

Hallo,

ich beschägtige mich zurzeit mit einem Programm in dem es sehr auf 
ablaufgeschwindigkeit ankommt.

Ich muss dabei eine if abfrage machen in der ich einfach zwischen True 
oder False unterscheide.
Nun könnte ich bei der if ja einfach schreiben "if(Variable_A)" was mich 
daran stört ist dass beide Fälle (True/False) für mich eigentlich 
Leitung1 und Leitung2 bedeutet. Deswegen würde ich es der Lesbarkeit 
halber lieber so schreiben "if(Variable_A == Leitung1)".

Ich frage mich, ob es unterschiede in der Auswertung gibt.
Weiß das jemand? Gibt es unterscheidungen zwischen einer Boolschen 
Abfrage und einem gleichwertigem Vergleich?

Gruß Skittler

von (prx) A. K. (prx)


Lesenswert?

Was die Optimierung angeht: Jeder brauchbare Compiler wird bei if(a != 
0) und if(a) den gleichen Code erzeugen. Bei if(a == 1) allerdings 
nicht, denn das hat eine andere Bedeutung.

Allerdings sei dringend empfohlen, true/false nur dort zu verwenden, wo 
das auch Sinn ergibt. Was hier nicht der Fall ist. Hier passt eine 
Enumeration besser. Wenn das auf's allerletzte Bit optimiert werden 
muss: if(a != 0) kann je nach Prozessor schneller sein als if(a == 1).

Wenn die Variable global ist und es sich um AVRs handelt: Für einzelne 
Bits haben diverse AVRs 3 freie Bytes im I/O-Bereich, die sehr effizient 
bitweise manipuliert und abgefragt werden können (GPIORx).

von Timmo H. (masterfx)


Lesenswert?

Das hängt vom Compiler und von dem Optimierungsgrad ab.
Am besten ist es wenn du dir einfach das Listfile ansiehst, das 
generiert wird. Beim x86 ändert sich nur ein Befehl.
Wenn du sowas machst wie
1
  if(i==1)
2
    c = 1;
3
  else
4
    c = 2;
Dann wird auf 1 geprüft. Wenn du schreibst
1
  if(i)
2
    c = 1;
3
  else
4
    c = 2;
Wird auf 0 geprüft. Aber nicht jede Architektur kennt die gleichen 
befehle. Manche können auf 0 Prüfen, aber nicht auf !=0.

von Maxi (Gast)


Lesenswert?

So ein,
1
if(a)
bedeutet
1
if(a != 0)

Von der Effizienz her dürfte das mit
1
if(a == 0)
vergleichbar sein.

Etwas anderes ist es, wenn Du mit bestimmten Werten vergleichst.
Etwa
1
if(a == 1)

Der Unterschied besteht darin, das viele Prozessoren, Befehle haben, die 
nach Rechen-Operationen (unter Umständen schon nach Ladeoperationen) das 
sogenannte Zero-Flag setzen.
Dann ist ein nachfolgendes
1
if(a)
oder auch
[c]
if(a == 0)
natürlich recht schnell anhand des Flags zu entscheiden.

Wenn aber mit anderen Werten als 0 verglichen wird, dann muessen die 
Operanden in der Regel tatsächlich nochmal durch eine Operation wie 
subtract, oder compare. Das kann je nach Breite des Datentyps auch 
mehrere Befehle beinhalten.

Die Breite spielt natürlich auch bei den == 0 und != 0 Vergleichen eine 
Rolle. Viele Compiler sind aber so schlau, das Z-Flag über mehrere Bytes 
mitzuschleppen.

Im Einzelfall hilft sicherlich ein Blick in das Assemblerlisting.

von Karl H. (kbuchegg)


Lesenswert?

Skittler wrote:
> Hallo,
>
> ich beschägtige mich zurzeit mit einem Programm in dem es sehr auf
> ablaufgeschwindigkeit ankommt.
>


Punkt 1
  Ich bezweifle ganz stark, dass dir diese 'Optimierung' den
  entscheidenenden Geschwindigkeitsschub bringt, der den Unterschied
  zwischen läuft und läuft nicht ausmacht. Auf der anderen Seite
  benötigt man manchmal wirklich nur die letzten paar Zehntel-Prozent
  an Laufzeit um in den grünen Bereich zu kommen und hat bereits alle
  algorithmischen Möglichkeiten ausgereizt.

Punkt 2
  Beide Konstrukte sind grundsätzlich mal nicht gleichwertig.

  Bei
    if( Variable_A )

  kann Variable_A irgendeinen Wert haben, solange er nicht 0 ist.

  Bei
    if( Variable_A == Leitung1 )

  wird hingegen gefordert, dass Variable_A exakt den Wert 1 haben muss.

  Bei dir macht das offenbar keinen Unterschied, da Variable_A per
  Definition nur die Werte 0 oder 1 haben kann (das stimmt doch,
  oder?). Aber wir alle wissen, dass sich Definition im Laufe eines
  Programmlebens auch mal ändern können. Und dann fallen einem genau
  diese kleinen Unterschiede auf den Kopf

Was du machen kannst
1
#define IS_LEITUNG_1(x)   (x)
2
3
4
....
5
6
7
   if( IS_LEITUNG_1( Variable_A ) )

Damit hast du an der Abfrage immer noch in lesbarer Form dokumentiert, 
was die Absicht des Vergleiches ist und kriegst trotzdem die 
möglicherweise etwas verminderte Laufzeit des Vergleiches auf nicht 0. 
Und falls sich mal an den Basisannahmen mal ws ändern sollte, hast du 
eine zentrale Stelle (das Makro) an der du das berücksichtigen kannst.

von P. S. (Gast)


Lesenswert?

Nichts gegen vorrauschauende Entwicklungsweisen, aber allgemein sollte 
man nur optimieren, was zu langsam ist - ansonsten sollte Lesbarkeit 
immer Vorrang haben.

von (prx) A. K. (prx)


Lesenswert?

Maxi wrote:

> Die Breite spielt natürlich auch bei den == 0 und != 0 Vergleichen eine
> Rolle. Viele Compiler sind aber so schlau, das Z-Flag über mehrere Bytes
> mitzuschleppen.

Das hängt eher von der Architektur (Befehlssatz) als vom Compiler ab.

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


Lesenswert?

Peter Stegemann wrote:
> Nichts gegen vorrauschauende Entwicklungsweisen, aber allgemein sollte
> man nur optimieren, was zu langsam ist - ansonsten sollte Lesbarkeit
> immer Vorrang haben.

"Never start optimizing before you have profiled it."

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch wrote:
> Peter Stegemann wrote:
>> Nichts gegen vorrauschauende Entwicklungsweisen, aber allgemein sollte
>> man nur optimieren, was zu langsam ist - ansonsten sollte Lesbarkeit
>> immer Vorrang haben.
>
> "Never start optimizing before you have profiled it."

Premature optimization is the root of all evil

                                 Donald E. Knuth

von Sven P. (Gast)


Lesenswert?

Und vorallem nicht die Leerlauf-Schleife optimieren... (K&R)

von Maxi (Gast)


Lesenswert?

@ A. K.

>Das hängt eher von der Architektur (Befehlssatz) als vom Compiler ab.

Hä? Wenn ich den C-Datentyp in einem_ Programm auf _einer Maschine 
variiere, dann hängt es sehr wohl vom Compiler ab, ob oder ob er nicht 
das Z-Bit mitschleppt.

Keine Ahnung was Du da gelesen hast.

von (prx) A. K. (prx)


Lesenswert?

Vielleicht reden wir aneinander vorbei.

Es gibt Architekturen, bei denen Vergleichsbefehle so kaskadiert werden 
können, dass man abschliessend ein Z-Flag für den Gesamtwert erhält. AVR 
ist ein Beispiel dafür. Andere Architekturen hingegen liefern im Z-Flag 
(soweit es sowas überhaupt gibt) stets nur die Information des zuletzt 
verglichenen oder subtrahierten Datenwortes, was bei Vergleichen von 
Datentypen jenseits der Wortbreite der Maschine zu längerem Code führt.

Und der Compiler kann nicht besser sein als die Zielmaschine hergibt. 
Wobei ich hoffnungsvoll davon ausgehe, dass jeder Compiler für AVR einen 
16- oder 32-Bit-Compare entsprechend umsetzt.

von Jomoel (Gast)


Lesenswert?

solche sachen wie

if(blala) sind meistens wenig durchdacht das erinnert mich an meine
studentenzeit wo es immer hiese


if(name)
  {assert blala
  strln blala
  strcpy blala
  }
 else blala


if(name) war immer vorhanden selbst wenn in name nur Müll drinnen stand
als wenn abfragen dann richrige

von Maxi (Gast)


Lesenswert?

@ A. K.

>Vielleicht reden wir aneinander vorbei.

Das halte ich für möglich.

Ich liefere hier doch keine umfassenden und widerspruchsfrei 
formulierten Analysen nur damit Du einen Streit um des Kaisers Bart 
haben kannst.

Bestätigung für Deine Ansichten findest Du in jedem guten Bucher über 
Compilerbau.


Nichts füt ungut.

von Maxi (Gast)


Lesenswert?

Im übrigen habe ich nicht von ArchitekturEN sonder von EINER Architektur 
gesprochen. Ist das jetzt klar? Mann, mann, mann.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Maxi schrob:
> Im übrigen habe ich nicht von ArchitekturEN sonder von EINER Architektur
> gesprochen. Ist das jetzt klar? Mann, mann, mann.

Von welcher Architektur denn?

Du schiebst nur was von "viele Architekturen" oben, und der OP bezog 
sich auch nicht speziell auf eine Architektur.

Maxi schrob:
> Der Unterschied besteht darin, das viele Prozessoren, Befehle haben, die
> nach Rechen-Operationen (unter Umständen schon nach Ladeoperationen) das
> sogenannte Zero-Flag setzen.

A.K. machte einige Anmerkungen speziell zu AVR, die allesamt korrekt 
sind.

Wenn es offenbar Missverständnisse gibt, solle man die ausräumen anststt 
rumzupöbeln, das ist meine bescheidene Meinung.

Missverständnisse sind sich nicht schlimmes. Es ist wesentlich 
erbaulicher, sie zu erkennen, auszuräumen und der Duskussion darauf 
ausbauend mehr Tiefe zu verleihen, als sich darüber zu erhitzen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. wrote:

> Es gibt Architekturen, bei denen Vergleichsbefehle so kaskadiert werden
> können, dass man abschliessend ein Z-Flag für den Gesamtwert erhält. AVR
> ist ein Beispiel dafür. [...]

> Und der Compiler kann nicht besser sein als die Zielmaschine hergibt.
> Wobei ich hoffnungsvoll davon ausgehe, dass jeder Compiler für AVR einen
> 16- oder 32-Bit-Compare entsprechend umsetzt.

Defür kann und derf er schlechter sein ;-)

Speziell für avr-gcc hatten wir das Thema ja schon des öfteren. Der 
AVR-Teil ist geschlagen mit dem, was die maschinenunabhängigen 
Optimierer, dir für i386 etc getunet sind, abliefern.

Nehmen wird mal folgendes kleines Testprogramm:
1
int foo (int y, int z)
2
{
3
    if (y) 
4
        return z;
5
    return 0;
6
}

Dafür liefert gcc die optimale Ausgabe
1
foo:
2
  or r24,r25
3
  brne .L4
4
  ldi r22,lo8(0)
5
  ldi r23,hi8(0)
6
.L4:
7
  movw r24,r22
8
  ret


Das Testprogramm verändern wir minimal zu einem Vorzeichen-Vergleich, 
bei
dem einfach auf Bit 15 von y getestet werden kann/könnte:
1
int foo (int y, int z)
2
{
3
    if (y < 0) 
4
        return z;
5
    return 0;
6
}

Dann lässt und gcc 4.f folgenden Code bewundern:

-- Er nimmt das High-Byte von y und macht einen 8-Bit Wert daraus
-- Aus diesem 8-Bit Wert mach er einen einen signed 16-Bit Wert
-- Er schiebt diesen Wert um 15 nach rechts (Ergebnis ist 0 oder -1)
-- Er maskiert z mit diesem Wert, das Ergebnis ist 0 oder z.

Klasse! Es werden keine Sprünge mehr gebraucht! Optimal für einen 
Boliden wie i386 (Das SBRC ist innerhalb der Komplementbildung, es ist 
kein Sprung für den Compiler). Für AVR ist es ne Strafe:
1
foo:
2
  # MSB extrahieren
3
  mov r18,r25
4
  # auf 16 Bit signed expandieren
5
  clr r19
6
  sbrc r18,7
7
  com r19
8
  # Um 15 nach rechts schieben
9
  lsl r19
10
  sbc r18,r18
11
  mov r19,r18
12
  # z mit der Maske verUNDen
13
  and r18,r22
14
  and r19,r23
15
  # return
16
  movw r24,r18
17
  ret

Die gleichen Kapriolen macht er wenn man auf Bit 15 von y testet und 
auch, wenn man das Testergebnis in eine Zwischenvariable speichert:
1
int foo (int y, int z)
2
{
3
    char x = y < 0;
4
    if (x) 
5
        return z;
6
    return 0;
7
}

Es ist also nicht offensichtlich und für den Programmierer nicht 
nachvollziehbar, wie der Compiler auf diesen Code kommt. 
Umformulierungen haben kaum eine Wirkung oder garkeine, weil die 
algebraisch das gleiche bedeuten.

Tipps kann man also praktisch keine geben, ausser den, möglichst 
verständlich zu programmieren und zu hoffen, daß eine neuere 
Compiler-Version besseren Code macht. Und nicht noch mehr Kapriolen.

Wenn man wirklich in einer konkreten Anwendung Zeitprobleme hat, die bei 
einem bestimmten Compiler auf solche überintelligenten Transformationen 
zurückzuführen sind, ist guter Rat teuer.

Allgemeine Tipps gibt es wie gesagt nicht. Der ergriffenen Optimierungen 
sind abhängig vom Compiler, seiner Version, seiner Beschalterung, der 
Zielarchitektur, dem Quellcode und der Kontext, in dem er steht und von 
der Menge an Information, die der Compiler hat.

Konkret für das Beispiel oben fällt mir nix ein ausser Hack, den ich 
hier nicht posten möchte ;-) Der Code wird damit zu
1
foo:
2
  ldi r18,lo8(0)
3
  ldi r19,hi8(0)
4
  sbrs r25,7
5
  movw r22,r18
6
.L4:
7
  movw r24,r22
8
  ret


Als Alternative andere Stellen suchen, wo sich was rausholen lässt. Aber 
da legt einen der Compiler womöglich auch aufs Kreuz...

von Martin W. (Gast)


Lesenswert?

Bei x86_64: Compare mit 0 gefolgt von JNE  bei if(a) bzw. if (a!=0) und 
Compare mit 1 mit JE bei if (a==1). JE ist near und JNE ist short.

von Klaus W. (mfgkw)


Lesenswert?

Lesbarkeit und Geschwindigkeit bekommt man vielleicht schöner zusammen 
mit einem switch:
1
enum eLeitung
2
{
3
  Leitung1,
4
  Leitung2,
5
};
6
7
...
8
9
  eLeitung   aktuelleLeitung = Leitung1;
10
11
  switch( aktuelleLeitung )
12
  {
13
    case Leitung1:
14
      // tun, was mit Leitung1 zu tun ist
15
      // ...
16
      break;
17
18
    case Leitung2:
19
      // tun, was mit Leitung2 zu tun ist
20
      // ...
21
      break;
22
23
    default :
24
      // sollte nie vorkommen, Fehler/Abbruch etc.
25
      break;
26
  }

von P. S. (Gast)


Lesenswert?

Klaus Wachtler wrote:
> Lesbarkeit und Geschwindigkeit bekommt man vielleicht schöner zusammen
> mit einem switch:

Vorsicht, ein switch ist oft langsamer. Ich hatte auch immer sowas im 
Ohr, ein switch sei bei integern viel besser - hat sich in der Praxis 
aber als falsch rausgestellt. Natuerlich kann sich das von Platform zu 
Platform auch wieder unterscheiden...

von Chris (Gast)


Lesenswert?

Bei Pic macht diese unterschiedliche IF Abfragen sehrwohl einen 
Unterschied in der Codegröße als auch in der Geschwindigkeit, welche 
jedoch vernachlässigbar ist. Weiters darf man nicht auf ==1 vergleichen,
da dies dann eine Konstante ist, sondern auf TRUE, wobei TRUE und FALSE 
so definiert werden:

#define FALSE 0
#define TRUE  !FALSE

oder

#define FALSE (1==0)
#define TRUE (1==1)

je nach Architektur und C Compiler bzw Optimierer.

von (prx) A. K. (prx)


Lesenswert?

Merkwürdige Compiler. Diese Ausdrücke sind nach der eigentlich üblichen 
Auswertung konstanter Rechnungen sowohl dem Typ als auch dem Wert nach 
gleich. !0 ist dann genauso eine Konstante wie 1.

von (prx) A. K. (prx)


Lesenswert?

Grad mal mit C18 ausprobiert. Bei 1==1 kommt bei Standard-C (also mit 
integer promotions) tatsächlich etwas anderes raus - aber schlechter. 
Die beiden anderen sind gleich.

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


Lesenswert?

Chris wrote:

> #define FALSE 0
> #define TRUE  !FALSE
>
> oder
>
> #define FALSE (1==0)
> #define TRUE (1==1)

Unfug.  Lies dir bitte die FAQ der Gruppe comp.lang.c durch, dort
wird ausgiebig diskutiert, warum es Unfug ist.

Wenn du einen C99-fähigen Compiler hast, dann nimm

#include <stdbool.h>

Das liefert dir den Typ bool mit den Werten true und false.  Ansonsten
nimm

#define FALSE 0
#define TRUE 1

von Chris (Gast)


Lesenswert?

True als !FALSE definiert ist ein Boolean,
hingengen TRUE als 1 definiert ist ein konstanter Integer oder Char,
was auch immer.
Bei micros hat man nicht immer einen C99 Compiler, und auch wenn man den
hat, heißt nicht, daß BOOL_ auch implementiert ist.

Ein Beispiel aus einer Faq von einem C99 Group

Why is a bool type an advantage? You can get a variety of opinions on 
whether this is a step forward. In C, common usage to mimic this type 
would be as follows:
        typedef int Bool;

        #define FALSE 0
        #define TRUE 1

One problem with such an approach is that it's not at all type-safe. For 
example, a programmer could say:
        Bool b;

        b = 37;

Hingegen, angenommen man hat keinen C99, dann wenn man
#define TRUE !FALSE
definiert hat, funktioniert das, als wenn es einen Bool-Type wäre,
da dann bei if(b==TRUE) das gleiche ist wie bei if(b), aber bei
if (b==1) oder auch (b==TRUE) wenn TRUE mit 1 definiert wird, das 
Ergebnis
schlichtwegs falsch ist.

von (prx) A. K. (prx)


Lesenswert?

Chris wrote:

> Hingegen, angenommen man hat keinen C99, dann wenn man
> #define TRUE !FALSE
> definiert hat, funktioniert das, als wenn es einen Bool-Type wäre,
> da dann bei if(b==TRUE) das gleiche ist wie bei if(b), aber bei
> if (b==1) oder auch (b==TRUE) wenn TRUE mit 1 definiert wird, das
> Ergebnis schlichtwegs falsch ist.

Wenn man keinen C99 hat, dann C89 - wenn wir bei Standards bleiben und 
individuelle Erweiterungen aussen vor lassen. C89 kennt kein "bool", 
daher ist !0 in Wert und Typ identisch mit 1==1 und mit 1.

Da C99 existierende Programme nicht allzu sehr über den Haufen wirft, 
kann sich ohne explizite Verwendung des Datentyps "bool" daran auch 
nicht viel ändern. Erst wenn Daten explizit als "bool" spezifiziert 
werden kann der Compiler anderen Code erzeugen, weil er andere Werte als 
0 und 1 ausschliessen darf.

Unterschiedliches Optimierungsverhalten von C89 und C99 setzt also 
voraus, dass man bei C89 irgendwo ein "typedef int bool;" oder sowas in 
der Art stehen hat. Unterschiedliches Ergebnis kriegt man aber auch dann 
nur, wenn was anderes als 0 oder 1 auftreten kann. Ist dann aber sowieso 
im undefinierten Bereich.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Stegemann wrote:
> Klaus Wachtler wrote:
>> Lesbarkeit und Geschwindigkeit bekommt man vielleicht schöner zusammen
>> mit einem switch:
>
> Vorsicht, ein switch ist oft langsamer. Ich hatte auch immer sowas im
> Ohr, ein switch sei bei integern viel besser - hat sich in der Praxis
> aber als falsch rausgestellt.

Jo, das hängt natürlich vom Compiler ab, wie er switch umsetzt.

Prinzipiell gibt es 3 Möglichkeiten:

Sprungtabelle
Der switch-Wert wird als Index in eine Sprungtabelle verwendet, in der 
die Adressen der einzelnen case-Labels stehen. Diese Strategie ist bei 
dicht besetzten case-Werten angebracht und wenn es eine bestimmte 
Mindestanzahl an Labels gibt.

Die Zeit zu einem Label ist konstant.

Spaghetti
Entspricht einem if {} else if {} ... else{} Spaghetti.
Empfehlenswert bei recht wenigen Labels oder dünn besetzten Indices.

Zeit ist linear.

Binäre Suche
Es wird Code erzeugt, der in if-else-Abfragen die Anzahl verbleibender 
Labels halbiert. Es werden also keine == oder != Vergleiche erzeugt wie 
bei Spaghetti, sondern zB < oder >= Vergleiche.

Die Vergleiche separieren Intervalle, die nur 1 Index enthalten, auf den 
dann explizit geprüft wird. Bei dicht besetzten Indices vereinfacht sich 
das etwas, weil keine default-Werte zwischen den Indices sind.

Zeit ist logarithmisch.

von (prx) A. K. (prx)


Lesenswert?

Und die Theorie sagt, dass der Compiler sich davon die beste Variante 
aussucht, unter Berücksichtigung des Optimierungsziels Platz/Zeit.

Die Praxis sagt leider manchmal etwas anderes. So kann es bei avr-gcc 
manchmal nützlich sein, die tabellengestützte Implementierung explizit 
auszuschliessen.

von Chris (Gast)


Lesenswert?

Sorry, aber laut ANSI-C ist 1==1 ein Bool type, wie auch !0
und 1 ein integer.

ein Beispiel:
#define FALSE 0
#define TRUE !FALSE
#define SWITCH_PORT PORTA
#define SWITCH_BIT  0x30
#define SWITCH_INV  0x30

#define SWITCH (SWITCH_PORT&SWITCH_BIT^SWITCH_INV)

if (SWITCH) { /*todo*/ }  // works always
if (SWITCH==TRUE) { /*todo*/ } // works, but
                               // true was defined as 1, then
if (SWITCH==TRUE) {} // would be expanded as
if ((PORTA&0x30^0x30)==1) {} //and a clever compiler could optimize it 
to
if (0) {} // and remove the code, or expand it at runtime always as 
false.

von (prx) A. K. (prx)


Lesenswert?

Chris wrote:

> Sorry, aber laut ANSI-C ist 1==1 ein Bool type, wie auch !0
> und 1 ein integer.

Das kann für traditionelles ANSI-C aka C89 schon deshalb nicht sein, 
weil es in da keinen solchen Datentyp gibt.

Nachgesehen: Das stimmt nicht einmal für C99: "The == (equal to) and != 
(not equal to) operators are analogous to the relational 93) operators 
except for their lower precedence. Each of the operators yields 1 if the 
specified relation is true and 0 if it is false. The result has type 
int."

von (prx) A. K. (prx)


Lesenswert?

Umgekehrt: Es besteht in C99 ein Unterschied zwischen
  bool b;
  if (b == 1)
und
  int b;
  if (b == 1)
weil der erste Fall aufgrund des begrenzten Wertebereichs auch als (b != 
0) implementiert werden darf. Auch hier ist es aber wieder egal, ob da 1 
oder !0 steht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Um mal wieder an den Anfang zu kommen:
> Nun könnte ich bei der if ja einfach schreiben "if(Variable_A)" was mich
> daran stört ist dass beide Fälle (True/False) für mich eigentlich
> Leitung1 und Leitung2 bedeutet. Deswegen würde ich es der Lesbarkeit
> halber lieber so schreiben "if(Variable_A == Leitung1)".

Ich würde (ganz pragmatisch) die Variable "Leitung1" nennen.
Dann könnte ich schreiben:
1
if (Leitung2) {} // != 0
bzw.
1
if (!Leitung2) {} // das wird dann wohl Leitung 1 sein

von Michael A. (micha54)


Lesenswert?

Johann L. wrote:
>
1
> int foo (int y, int z)
2
> {
3
>     if (y < 0)
4
>         return z;
5
>     return 0;
6
> }
7
>
>
> Dann lässt und gcc 4.f folgenden Code bewundern:
>
> -- Er nimmt das High-Byte von y und macht einen 8-Bit Wert daraus
> -- Aus diesem 8-Bit Wert mach er einen einen signed 16-Bit Wert
> -- Er schiebt diesen Wert um 15 nach rechts (Ergebnis ist 0 oder -1)
> -- Er maskiert z mit diesem Wert, das Ergebnis ist 0 oder z.
>
> Klasse! Es werden keine Sprünge mehr gebraucht! Optimal für einen
> Boliden wie i386 (Das SBRC ist innerhalb der Komplementbildung, es ist
> kein Sprung für den Compiler). Für AVR ist es ne Strafe:
>
>
1
> foo:
2
>   # MSB extrahieren
3
>   mov r18,r25
4
>   # auf 16 Bit signed expandieren
5
>   clr r19
6
>   sbrc r18,7
7
>   com r19
8
>   # Um 15 nach rechts schieben
9
>   lsl r19
10
>   sbc r18,r18
11
>   mov r19,r18
12
>   # z mit der Maske verUNDen
13
>   and r18,r22
14
>   and r19,r23
15
>   # return
16
>   movw r24,r18
17
>   ret
18
>

Hallo,

also mein Compiler erzeugt da was anderes:

int foo (int y, int z)
{
    if (y < 0)
  ac:  29 2f         mov  r18, r25
  ae:  33 27         eor  r19, r19
  b0:  27 fd         sbrc  r18, 7
  b2:  30 95         com  r19
  b4:  33 0f         add  r19, r19
  b6:  22 0b         sbc  r18, r18
  b8:  32 2f         mov  r19, r18
  ba:  26 23         and  r18, r22
  bc:  37 23         and  r19, r23
        return z;
    return 0;
}
  be:  c9 01         movw  r24, r18
  c0:  08 95         ret


Gruß,
Michael

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Michael Appelt wrote:
> Johann L. wrote:
>>
1
>>   clr r19
2
>>   ...
3
>>   lsl r19
4
>>   ...
5
>>
>
> Hallo,
>
> also mein Compiler erzeugt da was anderes:
>
1
>   ae:  33 27         eor  r19, r19
2
>   ...
3
>   b4:  33 0f         add  r19, r19
4
>   ...
5
>

Zum einen ist das nicht das, was der Compiler erzeugt, sondern die 
Ausgabe des Assemblers oder Disassemblers.

Zum zweiten ist CLR X nur syntaktischer Zucker für EOR X,X. Dito LSL X 
für ADD X,X.

Das einzige, was nicht von gcc kam, sind meine #-Kommentare

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.