Forum: Mikrocontroller und Digitale Elektronik Richtig Invertieren


von Sven W. (sickone4)


Lesenswert?

Hallo Leute,

ich wollte mich mal schlau machen, wie ich eine Variable korrekt 
invertieren kann.

Folgende Grundlage habe ich dazu:

ich habe eine Variable namens UD (Up-Down), welche wie folgt deklariert 
ist:
1
volatile uint8_t UD;

nun weise ich der Variable je nach Notwendigkeit im Programm entweder 
den Wert 1 oder 0 zu in Form von:
1
#define TRUE 1 
2
#define FALSE 0

im quellcode sieht dass dann z.b. so aus:
1
UD = TRUE;

wie kann ich dieses UD denn invertieren?
Bei Bits geht das ja mit PORTx ^= _BV(X);

meine sehr spektakuläre Lösung sieht wie folgt aus:
1
if ( UD == FALSE)
2
{
3
  UD = TRUE;
4
  goto next;  // Sprungmarke "next"
5
}
6
      
7
if ( UD == TRUE)
8
{
9
  UD = FALSE;
10
  goto next;
11
}
12
13
next: //...

Gruß Sven

von Alexander F. (alexf91)


Lesenswert?

Ich würde das anders definieren:

#define FALSE 0
#define TRUE (!FALSE)

invertieren kannst du dann wieder mit UD = !UD;

von Karl H. (kbuchegg)


Lesenswert?

Sven Weinmann schrieb:

> meine sehr spektakuläre Lösung sieht wie folgt aus:
>
>
1
> if ( UD == FALSE)
2
> {
3
>   UD = TRUE;
4
>   goto next;  // Sprungmarke "next"
5
> }
6
> 
7
> if ( UD == TRUE)
8
> {
9
>   UD = FALSE;
10
>   goto next;
11
> }
12
> 
13
> next: //...
14
>

wozu brauchst du denn den goto?
Den braucht kein Mensch.

In
   if( bedingung )
     statement1;
   else
     statement2;

wird nur eines der beiden Statements ausgeführt, abhängig davon ob 
bedingung zutrifft oder nicht.
D.h. dein von dir eingeführter goto macht nix anderes als das, was 
sowieso automatisch passiert, wenn du einen else-Zweig benutzen würdest.

Gerade wenn du Anfänger bist: du brauchst keinen goto! Wenn du versucht 
bist einen goto zu verwenden, dann machst du was falsch.
Es gibt zwar Anwendungen, in denen ein goto tatsächlich die einfachste 
Lösung darstellt, aber in diese Situation wirst du die nächsten 2 Jahre 
nicht kommen und wenn es soweit ist, dann wirst du das wissen. Ich 
selbst hab in 28 Jahren C-Programmieren keinen einzigen goto verbaut.

OK.
Also

   if( UD )
     UD = FALSE;
   else
     UD = TRUE;

oder in der C-typischen Kurzform, die auf die gleiche Idee rausläuft

   UD = UD ? FALSE : TRUE;

Oder

   UD = 1 - UD;

Oder

   UD = !UD;

von tobi (Gast)


Lesenswert?

Hab ich mal gesehen, und ist auch ganz nett:
1
#define true (1==1)
2
#define false (0==1)

von Fabian O. (xfr)


Lesenswert?

Als erstes brauchst Du true und false nicht selber definieren, dafür 
gibt es:
1
#include <stdbool.h>

Invertieren geht am einfachsten mit:
1
UD = !UD;

Gewöhn Dir aber lieber gleich an, Variablennamen wie üblich klein zu 
schreiben, damit man sie von Defines unterscheiden kann.

Da Du in Deinem Fall anscheinend eine Richtung definieren willst, wäre 
es am sinnvollsten, das auch explizit zu tun:
1
#include <stdint.h>
2
3
#define UP   0
4
#define DOWN 1
5
6
uint8_t direction = UP;
7
8
// Invertieren
9
direction = !direction;

Oder wenn es Dir besser gefällt:
1
#include <stdbool.h>
2
3
#define UP   false
4
#define DOWN true
5
6
bool direction = UP;
7
8
// Invertieren
9
direction = !direction;

von Sven W. (sickone4)


Lesenswert?

bei  UD = !UD;
oder direction = !direction

was passiert denn wenn der wert TRUE ist? wird der dann FALSE? und wenn 
er FALSE ist wird er TRUE? bzw in zahlen, wieso wird eine variable mit 
einem wert 1 wenn ich sie invertiere 0? oder eben wenn sie 0 ist 1=

von Peter II (Gast)


Lesenswert?

Sven Weinmann schrieb:
> wieso wird eine variable mit
> einem wert 1 wenn ich sie invertiere 0? oder eben wenn sie 0 ist 1=

das muss nicht so sein. Dann True ist definiert als !0 und nicht 1. Es 
kann also durchaus sein das aus 0 eine 255 oder eine 65536 wird.

von Sven W. (sickone4)


Lesenswert?

das war mein problem hier!

wobei ich selbst true ja als 1 und false als 0 definiert habe!

aber gerade da stellt sich mir die frage, woher weiß der controller 
denn, dass false das gegenteil von true ist?

von Michael (Gast)


Lesenswert?

Es gibt nur 1 oder 0. Wenn nicht 1, dann 0, wenn nicht 0 dann 1
Also ist "NICHT 1" automatisch 0 und "Nicht 0" muss daher 1 sein.

Also ist UD = !UD zu lesen als "neuer wert = nicht alter wert", womit 
wir wieder am Anfang wären

von Sven W. (sickone4)


Lesenswert?

wollte das nur klarstellen, damit da keine missverständnisse aufkommen! 
danke!

von Michael (Gast)


Lesenswert?

Ergänzung, weil ioch zu langsam war:

Sven Weinmann schrieb:
> aber gerade da stellt sich mir die frage, woher weiß der controller
> denn, dass false das gegenteil von true ist?

egal wie du definierst, ab deiner ersten Zuweisung von UD = true steht 
in UD nicht "true" sondern eben die 1, was anderes kann der Controller 
ja nicht speichern. Und hier kommt wieder NICHT 1 ist 0, was DU als 
false definiert hast (auslesen kannst du ja "false" nicht)

von Marius S. (lupin) Benutzerseite


Lesenswert?

Um das ganze zu klären kann man das auch einfach mal in C einhacken:
1
#include <stdio.h>
2
3
int main(int argc, char* argv[])
4
{
5
  int iint;
6
  bool bbool;
7
8
  bbool = true;
9
  printf("True ist: %.2X\r\n", *(char*)&bbool);
10
11
  bbool = false;
12
  printf("False ist: %.2X\r\n", *(char*)&bbool);
13
14
  bbool = !false;
15
  printf("!false ist: %.2X\r\n", *(char*)&bbool);
16
17
  bbool = !true;
18
  printf("!true ist: %.2X\r\n", *(char*)&bbool);
19
  
20
  bbool = ~false;
21
  printf("~false ist: %.2X\r\n", *(char*)&bbool);
22
23
  bbool = ~true;
24
  printf("~true ist: %.2X\r\n", *(char*)&bbool);
25
  
26
  if(-1) printf("-1 ist true!\r\n");
27
  if(0) printf("0 ist true!\r\n");
28
  if(1) printf("1 ist true!\r\n");
29
30
  getchar();
31
  return 0;
32
}

Die Ausgabe dazu:

True ist: 01
False ist: 00
!false ist: 01
!true ist: 00
~false ist: 01
~true ist: 01
-1 ist true!
1 ist true!

Die Konvertierung des Bools über Pointer habe ich gemacht um deutlich zu 
machen, dass das Programm den tatsächlichen Speicherinhalt des Bools 
anzeigt.

Es gibt zwei NOT-Operationen in C. Das ! ist ein logisches NOT. Das ~ 
ist ein binäres NOT.

Das beim binären NOT false zu 1 wird ist klar.

Eine Zahl ungleich von null ist immer true (ich hab es jetzt nur mit -1, 
0 und 1 probiert).

Das beim binären NOT true zu 1 wird liegt wohl daran, dass ein bool 
intern nicht aus einem Bit besteht (je nach Compiler kann es 
unterschiedlich lang sein, meist aber 8 bit).
Es werden alle Bits des Bools invertiert und der Boolsche Wert wird 
interpretiert. Da beim binären invertieren alle anderen Bits auf 1 
kippen wird die Zahl wieder als true interpretiert.

von Fabian O. (xfr)


Lesenswert?

Es ist eigentlich egal, wie true definiert ist, das Invertieren geht 
immer. Der !-Operator macht aus einem wahren Wert einen unwahren Wert 
und aus einem unwahren Wert einen wahren Wert:
1
#define TRUE 5
2
#define FALSE 0
3
4
uint8_t var;
5
6
var = TRUE; // var hat den Wert 5 (ungleich 0, also wahr)
7
var = !var; // aus wahr wird unwahr, d.h. var ist jetzt 0.
8
var = !var; // aus unwahr wird wahr, d.h. var ist jetzt 1
9
            // (vielleicht auch was anderes ungleich 0, z.B. 255).
10
var = !var  // aus wahr wird unwahr, d.h. var ist jetzt 0.

Das einzige was man lassen sollte sind Abfragen wie:
1
if (var == TRUE)

Denn wenn man TRUE nicht richtig definiert hat, geht das schief. Gerade 
bei fremden Funktionen kann man da reinfallen, wenn sie einen anderen 
Wert zurückliefern, den man als bool interpretiert. Also bei Abfragen 
immer nur
1
if (var != 0) bzw. if (var == 0)
oder kurz (und bei sinnvoller Variablenbennenug sehr gut lesbar)
1
if (var) bzw. if (!var)
verwenden.

von Sven W. (sickone4)


Lesenswert?

if (var) ist das gleiche wie if (var ==1) ?

von Marius S. (lupin) Benutzerseite


Lesenswert?

sven, if(var) ist das gleiche wie if(var!=0)

von Thomas E. (thomase)


Lesenswert?

Sven Weinmann schrieb:
> if (var) ist das gleiche wie if (var ==1) ?
NEIN!!!

if(var) ist das gleiche wie if(var == !0) oder if(var != 0)
Denn var könnte ja auch 143, -27 oder 172572373833 sein. Und dann ist es 
nicht 1.
Dann würde if(var) true und if(var == 1) false ergeben.

mfg.

von Marius S. (lupin) Benutzerseite


Lesenswert?

So ist es eigentlich noch schöner...

Hier sieht man direkt den Zahlenwert, ohne dass der Compiler da noch was
rum-interpretiert. Bei der Ausgabe des ~true hat der Compiler vorher den
Wert in true interpretiert. Mit diesem Code sieht man jetzt auch warum:
1
#include <stdio.h>
2
3
int main(int argc, char* argv[])
4
{
5
  printf("True ist: %X\r\n", (int)true);
6
  printf("False ist: %X\r\n", (int)false);
7
  printf("!false ist: %X\r\n", (int)!false);
8
  printf("!true ist: %X\r\n", (int)!true);
9
  printf("~false ist: %X\r\n", (int)~false);
10
  printf("~true ist: %X\r\n", (int)~true);
11
  
12
  if(-1) printf("-1 ist true!\r\n");
13
  if(0) printf("0 ist true!\r\n");
14
  if(1) printf("1 ist true!\r\n");
15
16
  getchar();
17
  return 0;
18
}

Ausgabe:
True ist: 1
False ist: 0
!false ist: 1
!true ist: 0
~false ist: FFFFFFFF
~true ist: FFFFFFFE
-1 ist true!
1 ist true!

von Fabian O. (xfr)


Lesenswert?

Sven Weinmann schrieb:
> if (var) ist das gleiche wie if (var ==1) ?

Nein, eben nicht.
1
if (var)
bedeutet "falls der Wert wahr ist" und "wahr" ist in C alles, was nicht 
0 ist. Es ist also das gleiche wie:
1
if (var != 0)

Deshalb ist es ja so gefährlich, sich TRUE per Define zu definieren, 
weil es dann nur einen bestimmten Wert hat (z.B. 1) und nicht "alles 
ungleich 0" bedeutet, wie es eigentlich sein müsste.

von Marius S. (lupin) Benutzerseite


Lesenswert?

Ich glaube Svens frage ist jetzt beantwortet. Lustig wie sich alle immer 
auf die einfachen Fragen stürzen (mich eingschlossen :)).

Ich sehe kein Problem TRUE per Define zu definieren. So lange man nicht 
definiert:
#define TRUE 0
#define FALSE 1

Das könnte wohl zu Problem führen :-)

von Sven W. (sickone4)


Lesenswert?

danke euch allen^^

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Sven Weinmann schrieb:
>> wieso wird eine variable mit
>> einem wert 1 wenn ich sie invertiere 0? oder eben wenn sie 0 ist 1=
>
> das muss nicht so sein. Dann True ist definiert als !0 und nicht 1. Es
> kann also durchaus sein das aus 0 eine 255 oder eine 65536 wird.

Das kann allerdings nicht sein.

  !0   ergibt   1

das ist so definiert.
Wenn der Compiler einen 'boolschen Wert' zu erzeugen hat, dann wird für 
das Ergebnis True IMMER 1 herauskommen.

Daher ist das Ergebnis für
   i < j
entweder 0 oder 1, je nach den aktuellen Werten der Variablen. Aber das 
Ergebnis dieses Ausdrucks kann nicht 2 oder 8 oder 255 oder 65536 sein. 
Die Regelung mit 'ungleich 0' gilt nur in der Verwendung eines 
Ausdrucks. Dort wird jeder Wert ungleich 0 als logisch wahr gewertet. 
Wenn aber aus einem Ausdruck ein logischer Wahrheitswert resultiert (wie 
zb die Ergebnisse der logischen Operatoren &, |, !, aber auch 
Vergleiche) dann wird der Wert 'logisch wahr' durch 1 repräsentiert. Der 
Compiler muss dafür Sorge tragen, dass nur die beiden Ergebnisse 0 und 1 
möglich sind.

Das Ergebnis von

   int i = 8;
   i = !!i;

ist also definitiv und garantiert eine 1 in i.

von Sven B. (scummos)


Lesenswert?

Eine weitere sichere und konsistente Methode die mir einfällt ist
1
#define true (1 == 1)
2
#define false (1 == 0)
3
4
int x = true;
5
x = x == false; // invertieren

oder (etwas aufwendiger aber dafür weiß man genau was drinsteht):
1
#define true 1
2
#define false 0
3
4
int x = true;
5
x = x > 0 ? 0 : 1; // invertieren

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.