Verwirrung: nur 1 ist true

Ich habe ja folgendes gelernt:
false ist 0
true ist alles Andere als 0

Und auch in der Arduino-Referenz steht es so zu lesen:

false is defined as 0 (zero).

Any integer which is non-zero is true, in a Boolean sense. So -1, 2 and -200 are all defined as true, too, in a Boolean sense.

Um das zu überprüfen könnte man folgendes Programmbeispiel (1) schreiben:

void setup() {
  Serial.begin(9600);
  for (int i = -3; i < 4; i++) {
    Serial.print("i: ");
    Serial.print(i);
    if (i)
      Serial.print("   true");
    if (!i)
      Serial.print("   false");
    Serial.println();
  }
}

void loop() { }

Das Ergebnis ist (wie zu erwarten):

i: -3   true
i: -2   true
i: -1   true
i: 0   false
i: 1   true
i: 2   true
i: 3   true

ABER, wenn ich den Code so schreibe (Programmbeispiel 2):

void setup() {
  Serial.begin(9600);
  for (int i = -3; i < 4; i++) {
    Serial.print("i: ");
    Serial.print(i);
    if (i == true)
      Serial.print("   true");
    if (i == false)
      Serial.print("   false");
    Serial.println();
  }
}

void loop() { }

bekomme ich folgendes Ergebnis (Arduino-IDE 1.8.6):

i: -3
i: -2
i: -1
i: 0   false
i: 1   true
i: 2
i: 3

Also plötzlich scheint zu gelten:
0 == false (wie zu erwarten)
1 == true
und alles Andere ist weder noch :o :o

Hat jemand eine Idee wie es dazu kommt.
Habe ich etwas übersehen oder falsch verstanden?
Ich hätte ja bei beiden Programmbeispielen das gleiche Ergebnis erwartet.

vieleicht kanns einer der alten besser erklären, ich probiere es mal so:

es wird nicht zu "weder noch" sondern du fragst was anderes ab bzw. hast eine andere Bedingung erstellt

if (!i) ... so viel wie "ist nicht true" -> also wird jeder Ausdruck mit i ungleich 0 logisch true.

if (i==false) ... vergleichbar mit if (i== 0) daher bekommst du nur bei i = 0 dein Print false.

Hat jemand eine Idee wie es dazu kommt.
Habe ich etwas übersehen oder falsch verstanden?

Die Regeln für die impliziten Konvertierungen überlesen?

 if (i == false)

Hier findet ein impliziter Cast statt. (eigentlich sogar zwei)
Solche Casts erfolgen bevorzugt vom einfacheren/kleineren Daten Type zum größeren, um möglichst keine Daten zu verlieren.

if (i == false)

Wird damit zu
if (bool(i == int(false)))

Du erwartest aber
if (bool(i) == false)

Da liegt die Ursache!


Du hast jetzt einen Grund gefunden, warum ich jedes mal Pickel bekomme, wenn ich Vergleiche mit true oder false sehe.
Scheint aber irgendwie ein Hobby zu sein...
Im Grunde habe ich aufgegeben die Leute überzeugen zu wollen.

Die allgemeine Begründung ist meist: Es ist besser lesbar.
Mag ja auch stimmen, ist aber dabei auch viel Fehler trächtiger!
(und damit eine Dummheit)

if (!i) // gut
if (not i) // gut
if (i == false) // böse

Mantra:

Sei explizit!

Ich glaube irgenwo in den Eingeweiden von Arduino ist
#define true 1”
zu finden.
Darum vergleichst Du in “if (i == true)” die Variable mit 1 und das ist dann nicht das gleiche als wenn Du in “if (i)” die Variable selbst als Argument des IFs nimmst.

Grüße Uwe

Hallo,

Vergleiche auf true oder false sind nicht falsch. Können per Definition nicht falsch sein. Voraussetzung ist - wie immer - man nutzt die Datentypen richtig. Wenn man eine bool Variable immer auf true oder false setzt und darauf vergleicht, dann kann gar nichts schief gehen. Geht einfach nicht.

Das von uxomm erkannte Problem beruht ja nur darauf, weil der falsche Datentyp verwendet wurde - für den Test.
Alle anderen Vergleichspraktiken sind nur ein Missbrauch dessen, denn eine bool Vergleichsvariable kann per Definition eigentlich nichts anderes sein wie 0 oder 1. Man kann mit Software viel Unsinn machen, was man in einer Logik Hardwareschaltung so nie machen könnte.

Du möchtest nicht vestehen... scheint mir...

Wie oft sieht man
if(digitalRead(pin)==true)

Das tut mir so weh, dass ich mich von solchen Threads meist abwende.
Wer sowas macht, der isst auch kleine Kinder :smiling_imp:

Das ist erstens eine unnötoge Redundanz, und damit automatisch böse.

Und zweitens gibt digitalRead einen int und keinen bool zurück.

Man ist mit dem Vergleich also genau in dem Bereich, um den es sich in diesem Thred dreht.
Unbeabsichtigte implizite Konvertierungen, welche in die Hölle führen (können)

Hallo,

combie:
Wie oft sieht man
if(digitalRead(pin)==true)

Das tut mir so weh, dass ich mich von solchen Threads meist abwende.
Wer sowas macht, der isst auch kleine Kinder :smiling_imp:

Das ist erstens eine unnötoge Redundanz, und damit automatisch böse.

Und zweitens gibt digitalRead einen int und keinen bool zurück.

Man ist mit dem Vergleich also genau in dem Bereich, um den es sich in diesem Thred dreht.
Unbeabsichtigte implizite Konvertierungen, welche in die Hölle führen (können)

naja, nach Arduino-Beschreibung gibt es HIGH oder LOW zurück.
Genau das macht es auch. Wäre ja auch recht sinnlos von einem Digital-Pin ein int zurückzugeben.
Nun ist irgendwo HIGH als 1 und LOW asl 0 definiert. Macht ja auch Sinn, HIGH und LOW würde z.B. ein sbi/cbi auch kaum verstehen.

Warum die das als int zurückgeben wissen also wohl nur die Programmierer des Core.
Macht es aber einem Einsteiger nicht einfacher.
if(digitalRead(pin)==HIGH) wäre ja sinnvoller oder
if(digitalRead(pin)==1)

Aber ein DigitalPin kann ja nur 0 oder 1 sein wenn der AVR nicht kaputt ist...
Dummerweise ist aber ja falls 0 und true alles anderen, damit passt praktisch
if(digitalRead(pin)==true)
eben auch ohne Ausnahme immer, egal, ob uns oder dem Compiler dabei ein paar graue Haare wachsen...

PS:
float test;
...
if (test == 23)
ist da viel schlimmer zum Fehler suchen.

Gruß aus Berlin
Michael

Gruß aus Berlin
Michael

if(digitalRead(pin))

wäre vollkommen ausreichend.
Die implizite Konvertierung von int nach bool zeigt genau das Verhalten, welches z.B. uxomm erwartet hat, aber nicht bekommen sollte.

Warum die das als int zurückgeben wissen also wohl nur die Programmierer des Core.

So ist es wohl.
Da gibts noch mehr Stellen, zu denen man ähnliches sagen könnte.

Aber ein DigitalPin kann ja nur 0 oder 1 sein wenn der AVR nicht kaputt ist…
Dummerweise ist aber ja falls 0 und true alles anderen, damit passt praktisch
if(digitalRead(pin)==true)
eben auch ohne Ausnahme immer, egal, ob uns oder dem Compiler dabei ein paar graue Haare wachsen…

Ich könnte dir ja zustimmen, wenn da nicht die Gewöhnung wäre.
Denn, was man an einer Stelle tut, wird man auch irgendwann an anderen Stellen so tun.
Und damit ist es sicherlich eher ein Frage, “Wann” man damit auf die Nase fällt, und nicht “Ob”.

Ich für mich selber bin mir zu 100% sicher, dass ich mir sowas nicht angewöhnen will.
Kann auch nur jedem anderen davon abraten.
Ob das angenommen wird, ist mir dabei recht egal.

Aber ein DigitalPin kann ja nur 0 oder 1 sein wenn der AVR nicht kaputt ist…

Du programmierst dann gegen die Implementierung von digitalRead().
Das tut man nicht, darum gehört es zu meinen Mantras:

Programmiere immer nur gegen das Interface,
nie gegen die Implementierung.

Und das Interface von digitalRead(), ist (wie du schon sagtest) auch recht kaputt.
Eigentlich kann ich dazu nur sagen, dass man Fehler nur selten beheben kann, wenn man da noch einen weiteren drauf setzt.
Und die doppelte implizite Konvertierung ist kaum zu überblicken. Da unsichtbar.

Eine einfache implizite Konvertierung ist ausreichend.
Die zweite, ist eine unnötige Redundanz.
Und damit tendenziell eher Fehler verursachend, als hilfreich.

Ich komme mir schon vor, wie ein Priester…
Darum gebe ich lieber Ruhe.

Aber Recht hast Du, wenn man es genau betrachtet.

Ich selbst verwende auch eher die direkte Variante (if (digitalRead())). Ich habe mich aber schon dabei ertappt, dass ich bei Code für Anfänger das "== true" benutzt habe. Das werde ich in Zukunft weg lassen.

Gut, dass boolean auf bool zeigt. Ich bin das boolean aus der JAVA-Zeit noch gewöhnt. Das Entwickeln gegen das Interface war bei und da auch Pflicht. Es gab sogar zu jeder Klasse eine Interfaceklasse, gegen die programmiert wurde.

Gruß Tommy

Hallo,

Tommy56:
Aber Recht hast Du, wenn man es genau betrachtet.

Ich selbst verwende auch eher die direkte Variante (if (digitalRead())). Ich habe mich aber schon dabei ertappt, dass ich bei Code für Anfänger das "== true" benutzt habe. Das werde ich in Zukunft weg lassen.

sicher hat er Recht. Ich selbst benutze entweder auch (if digitalRead()) oder aber (if (digitalRead() == HIGH)) wenn ich für mich selber beim rüberschauen sofort erkennen will, ob ich auf HIGH oder LOW teste.
Das (if digitalRead()) oder eben (if !digitalRead()) zwingt doch zu genauerem Hinschauen.

Gruß aus Berlin
Michael

Danke für die Antworten!

In "eigenen" Programmen verwende ich

if (digitalRead(pin) == true)

eigentlich schon lange nicht mehr.
Schon allein wegen des geringeren Tippaufwandes :slight_smile: schreibe ich viel eher:

if (digitalRead(pin))

Und weil digitalRead ja "fürchterlich langsam" ist, greife ich auch oft direkt auf die Ports zu.

Aber wenn ich mit (manchmal recht jungen) "Totalanfängern" Programme schreibe, dann ist man versucht möglichst "anschauliche" Beispiele zu geben. Andererseits will ich möglichst wenige "Wege die in die Hölle führen" weisen. :o
Die richtige Balance zu finden ist nicht immer einfach.

Die impliziten Konvertierungen führen offensichtlich mitunter zu Aquaplaning und Glatteisbildung :slight_smile:

Und die Arduino-Referenz ist auch nicht soooo hilfreich:

Any integer which is non-zero is true, in a Boolean sense. So -1, 2 and -200 are all defined as true, too, in a Boolean sense.

uwefed:
Ich glaube irgendwo in den Eingeweiden von Arduino ist
"#define true 1"
zu finden.

Ja, das hatte ich auch irgendwo gelesen, habe (im Quellcode) danach gesucht, aber es bislang nicht gefunden - muss wohl sehr tief in den Eingeweiden stecken :slight_smile:
Aber auch wenn ich es nicht finde kann ich ruhig schlafen :slight_smile:

Fazit:
Auch dass das ganz einfach Scheinende, wie "true", kann ziemlich komplex sein.

Nochmals danke für die Beiträge!

muss wohl sehr tief in den Eingeweiden stecken

Bei mir:

E:\Programme\arduino\hardware\tools\avr\lib\gcc\avr\5.4.0\include\stdbool.h

Gehört also zum Lieferumfang des Gcc

Oh, danke!

Ja, genau im “Lieferumfang” hatte ich gesucht.
Und weiß jetzt auch, warum ich es nicht gefunden habe.
Wie so oft, geht es um Details :slight_smile:
In stdbool.h steht:

#define true	1

und das Zeichen zwischen true und 1 ist ein Tabulatorzeichen…

Ich hatte nur nach (ein oder mehreren) Leerzeichen gesucht.
Hätte wohl besser nach “allegmeinem Whitespace” suchen sollen.

Man lernt täglich dazu :slight_smile:

Besten Dank!

Hallo,

mein Text war eigentlich eindeutig. Im Eröffnungsthread ging es rein um true und false. Also reine bool Zustände. Darauf bezog sich meine Antwort. Es ging nicht um digitalRead im Zusammenhang mit if. Soviel zur Richtigstellung.
Abweichend davon ist eure Diskussion um if mit digitalRead natürlich korrekt.

Im Eröffnungsthread ging es rein um true und false. Also reine bool Zustände.

Könnte man denken!
Aber in Wirklichkeit ging es um implizite Konvertierungen, und welche Streiche sie einem spielen können.

Du triffst hier eine Feststellung:

Vergleiche auf true oder false sind nicht falsch. Können per Definition nicht falsch sein. Voraussetzung ist - wie immer - man nutzt die Datentypen richtig. Wenn man eine bool Variable immer auf true oder false setzt und darauf vergleicht, dann kann gar nichts schief gehen. Geht einfach nicht.

Dieser Feststellung kann ich unumwunden zustimmen!

Allerdings halte ich Vergleiche mit true oder false, eigentlich generell für flüssiger als Wasser.
Für überflüssig.
Ich wüsste jetzt wirklich nicht, ob, oder für was, ich das jemals gebraucht hätte.

Meine bescheidene Meinung ist, wenn man irgendwas ohne jeden Schaden weglassen kann, dann sollte man das auch tun.

Wann ist ein solcher Vergleich wirklich nötig, oder die bessere Wahl?
(ich weiß es nicht)

PS:
Ohne es jetzt geprüft zu haben, vermute ich mal, dass der Compiler das sowieso entsorgt.

Dem kann ich zustimmen! :wink:

Ich habe bis jetzt in Bsp. Sketchen für Neulinge bool Vergleiche immer ausführlich geschrieben. Damit sie sehen auf was überhaupt verglichen wird. Werde mir das abgewöhnen und nur noch im Kommentar hinterlassen.

Korrektur:

Sorry, Im Traum, oder so, ist mir aufgefallen, dass ich Gestern teilweise Quatsch erzählt habe.
Und heute morgen stand es wie ein Bild vor mir.

Hier also die Korrektur/Konkretisierung:

if(digitalRead(pin)==true)

Macht natürlich keine doppelte Konvertierung!
Sondern nur eine einfache.

Der Operator == liefert schon einen bool
Da wird also kein zweites mal konvertiert.

Natürlich mildert das das Problem nicht wirklich, da immer noch das unsichtbare einem Streiche spielen kann/wird.

Beispiel:

// Problematisch
int i = 3;
if (i == false)

Wird vom Kompiler so abgehandelt:

// Problematisch
int i = 3;
if (i == int(false))

Was laut Eingangsposting unerwünscht ist.

// besser, weil explizit
int i = 3;
if (bool(i) == false)

Liefert das korrekte/gewünschte Ergebnis, ist nur leider viel Schreibarbeit.
Und ist darum auch eher Fehlerträchtig

// besser, weil explizit und voll ausreichend
int i = 3;
if (not bool(i))
// besser, weil voll ausreichend
int i = 3;
if (not i)

Das ! oder not, erzwingt schon eine Konvertierung zu bool.

// besser, und für schreibfaule
int i = 3;
if (!i)

Grundsätzlich gibt es gegen implizite Konvertierungen nichts einzuwenden, wenn man weiß, was man da tut, bzw. wozu man den Kompiler veranlasst.
Problematisch wirds, wenn eigene Meinung und Regeln des Kompilers, sich widersprechen.
In den Punkten, wo Unsicherheit herrscht, kann man dann gerne explizit sein.
in gewissem Maße erhöht es sogar die Lesbarkeit, weil es klar macht, was beabsichtigt ist.

Hallo,

Doc_Arduino:
Ich habe bis jetzt in Bsp. Sketchen für Neulinge bool Vergleiche immer ausführlich geschrieben. Damit sie sehen auf was überhaupt verglichen wird. Werde mir das abgewöhnen und nur noch im Kommentar hinterlassen.

bei Neulingen hätte ich folgendes Problem und hier bleibe ich jetzt mal speziell bei digitalRead():

if (digitalRead()) und if (!digitalRead()) erfüllt prinzipiell seinen Zweck.
if (digitalRead() == true) if (digitalRead() == false) haben wir schon "durchgekaut".

Ich würde hier in diesem Fall immer if (digitalRead() == HIGH) oder if (digitalRead() == LOW) benutzen.

Du erklärst den Neueinsteiger, daß ein Zustand wahr ist, wenn ein Taster gedrückt ist. Der Taster hängt wie meist üblich gegen GND. Es kommt also 0 zurück und das wäre false...
Die Erklärung, daß der Pin LOW meldet, wenn der Taster gedrückt ist (zur Not eben auch 0), wäre wesentlich einprägasmer. Spätestens, wenn sie solch ein Code-Stück im Nachhinein nochmal durchgehen.
Auch sachen wie "der Ausgang von IC ist Low-aktiv" bleiben da verständlicher.
µC sind für mich da einfach zu sehr Hardware nah.

Auch "unnütze" Klammern in komplexeren Ausdrücken sind mir da lieber als Diskussionen darüber, daß die Abarbeitungsreihenfolge und die Priorität der Operatoren doch in jedem C-Buch erklärt werden.

Soll der Compiler das passend zusammenoptimieren, dazu ist er Compiler geworden. Laufzeitunterschiede, weil man mit den Klammern in die Optimierungsmöglichkeiten eingreift, sind doch nur an sehr wenigen Stellen wirklich von realer Bedeutung.

Nur meine Meinung...

Gruß aus Berlin
Michael

Ich würde hier in diesem Fall immer if (digitalRead() == HIGH) oder if (digitalRead() == LOW) benutzen.

Gegenvorschlag:

 // Low Aktiv , da interner Pullup
#define PRESSED LOW 
#define RELEASED HIGH

 if (digitalRead(pin) == PRESSED) ...;

 if (digitalRead(pin) == RELEASED) ...;

Nicht, dass ich solche Defines gut leiden kann, aber so wird klar lesbar, was gemeint ist, ohne dass man den Schaltplan dazu lesen muss

Laufzeitunterschiede, weil man mit den Klammern in die Optimierungsmöglichkeiten eingreift, sind doch nur an sehr wenigen Stellen wirklich von realer Bedeutung.

Ich bezweifle dass die Klammerung, auch eine übertriebene Klammerung, irgendeine Auswirkungen auf den generierten Code hat.
Natürlich, kann eine falsche Klammerung falschen Code erzeugen. Aber das sollte eh klar sein.

Hallo,

combie:
Ich bezweifle dass die Klammerung, auch eine übertriebene Klammerung, irgendeine Auswirkungen auf den generierten Code hat.
Natürlich, kann eine falsche Klammerung falschen Code erzeugen. Aber das sollte eh klar sein.

das mit den #define mache ich für mich ganz gern, wollte es aber nicht so laut sagen. :wink:

Es gab mal im mikrocontroller.net Diskussionen dazu, da waren auch Leute vertreten, die an der gcc-Implemetierung für die AVR beteiligt waren, u.a. Jörg Wunsch.
Wird geklammert, werden diese Ausdrücke generell im Code erstmal bearbeitet, ohne Klammern und in logischer Reihenfolge der C-Konventionen bricht er aber bereits ab, wenn die komplette Bedingung nicht mehr wahr werden kann, weil ein Teilausdruck bereits falsch ergibt. Oder so ähnlich.

Ich hör jetzt lieber auf, bin nur Hobbyprogrammierer...

Gruß aus Berlin
Michael