Forum: PC-Programmierung IF-ELSE ohne Anweisung im else-Zweig


von Sven Schol (Gast)


Lesenswert?

Ich habe in einem fremden Code einen komischen IF-ELSE-Konstrukt 
gefunden:

In einer Funktion steht folgendes:

if( count = 100 )
{
   // mache etwas
}
else

switch(time)
{
   case:    //usw.
   default: //usw.
}


Gehört die switch-ANweisung noch zum ELSE-Zweig? Nein oder, weil dort 
meiner Meinung nach doch die {}-Umklammerung fehlt.

Also dachte ich eher, dass ganze wäre mit folgendem äquivalent:

if( count = 100 )
{
   // mache etwas
}
else
{
}

switch(time)
{
   case:    //usw.
   default: //usw.
}

Doch leider ist die Funktionalität dadurch eine andere. Kann mir das 
bitte jemand erklären? Das gehört doch auf keinen Fall dem 
ANSI-C-Standard an?

VIELEN DANK.

von Stefan E. (sternst)


Lesenswert?

Sven Schol schrieb:

> Gehört die switch-ANweisung noch zum ELSE-Zweig?

Ja.

> Nein oder, weil dort
> meiner Meinung nach doch die {}-Umklammerung fehlt.

Bei nur einer Anweisung braucht man keine Klammern.

> Das gehört doch auf keinen Fall dem
> ANSI-C-Standard an?

Doch, und genauso jedem anderen C-Standard.

von P. S. (Gast)


Lesenswert?

Jedes C-Buch gibt darueber Auskunft. Und auch, warum es eine dumme Idee 
ist, die Klammern wegzusparen (dangling else problem), obwohl es erlaubt 
ist. Kurz gefasst: Nach dem else kommt ein Statement, das kann ein Block 
sein, muss aber nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Gehört die switch-ANweisung noch zum ELSE-Zweig?

Ja, das tut sie.

> Nein oder, weil dort
> meiner Meinung nach doch die {}-Umklammerung fehlt.

Die ist nur erforderlich, wenn ein kompletter Block abgegeben werden 
soll.


Es ist aber
1
if (a == 1)
2
  b = 2;
3
else
4
  b = 4;
gleichbedeutend mit
1
if (a == 1)
2
{
3
  b = 2;
4
}
5
else
6
{
7
  b = 4;
8
}


> Das gehört doch auf keinen Fall dem ANSI-C-Standard an?

Doch, das tut es, denn der else-Zweig ist nicht leer.

von Federtier (Gast)


Lesenswert?

Weils Thema gerade soweit passt; mir sind auch schon 2 "seltsame" 
Konstrukte untergekommen, bei denen ich aber fast sicher bin, dass man 
hier was kürzen kann:
1
if (Vergleich)
2
{
3
  MachWas();
4
}
5
else
6
{
7
}

sowie
1
if (Vergleich)
2
{
3
  MachWas();
4
}
5
else if (!Vergleich)
6
{
7
  MachAnders();
8
}

Beim ersten kann man doch das gesamte else weglassen, beim 2. den 2. 
Vergleich. Oder gibts nen Grund, wieso man Code so schreibt bzw. 
schreiben sollte?

von Erik W. (exor)


Lesenswert?

hm sieht mir fast wie automatisch generierter code aus ner state-machine 
oder so aus

von Karl H. (kbuchegg)


Lesenswert?

Ab und zu mache ich auch sowas
1
  if( Vergleich )
2
    ;
3
  else {
4
    ...
5
  }

in der finalen Version wird das dann natürlich korrigiert :-)


---------------------------------------------------
1
if (Vergleich)
2
{
3
  MachWas();
4
}
5
else if (!Vergleich)
6
{
7
  MachAnders();
8
}

Da gibts auch Varianten dazu, die man häufiger sieht.
1
  if( x >= 100 )
2
    mach was
3
  else if( x < 100 )
4
    mach was anderes

Wenn x nicht größer/gleich 100 ist, dann kann es nur kleiner als 100 
sein. Der Vergleich bei else ist also überflüssig.

Oder
1
  unsigned char x = ....;
2
3
  if( x >= 0 && x < 100 )
4
    mach was;
5
  else if( x >= 100 && x < 150 )
6
    mach was anderes;
7
  else if( x >= 150 && x <= 255 )
8
    mach noch was
mindestens die Hälfte der Vergleiche sind überflüssig :-)
Die Grenzen bei 0 und 255 sollten klar sein.
Aber im ersten else if: an dieser Stelle MUSS x schon größer/gleich 100 
sein, ansonsten wäre man nie hier hin gekommen, sondern bereits beim 
ersten if gelandet.

--->
1
  unsigned char x = ....;
2
3
  if( x < 100 )
4
    mach was;
5
  else if( x < 150 )
6
    mach was anderes;
7
  else
8
    mach noch was

von gast (Gast)


Lesenswert?

doch nämlich folgendes:

if (Vergleich)
{
  MachWas();
}
else if (!Vergleich)
{
  MachAnders();
}

als geschrieben:
void MachWas(void)
 {
  ....
  g_go = 0;
  ....
 }

void MachWasAnders(void)
 {
  ...
  g_go = !g_go;
  ...
 }
...
if (g_go)
{
  MachWas();
}
else if (!g_go)
{
  MachAnders();
}

...


bitte nciht verwechseln mit gogo girls ;)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

gast schrieb:
> doch nämlich folgendes:
>
> if (Vergleich)
> {
>   MachWas();
> }
> else if (!Vergleich)
> {
>   MachAnders();
> }

Nö.


> als geschrieben:
> (...)
>
> if (g_go)
> {
>   MachWas();
> }
> else if (!g_go)
> {
>   MachAnders();
> }
>

Wenn MachWas aufgerufen wird, wird der Else-Zweig nie aufgerufen, und 
also auch der enthaltene Vergleich nicht, und also MachAnders auch 
nicht.

von horst (Gast)


Lesenswert?

Wenn der Vergleich Seiteneffekte hat, dann kommt bei zwei Vergleichen 
hintereinander nicht unbedingt das selbe Ergebnis heraus.


uint8_t nurEinmalFalsch()
{
    static uint8_t rueckgabe = 0;

    if (rueckgabe)
       return rueckgabe;
    rueckgabe++;
    return 0;
}
void blah()
{}
void blup()
{}

# define RICHTIG    1
void main (void)
{
if (nurEinmalFalsch() == RICHTIG)
{
    blah();
} else if ( ! (nurEinmalFalsch() == RICHTIG) )
{
    blup();
}
}

Oder jemand wollte noch einmal daran erinnern, wann der else Zweig 
ausgeführt wird, weil das if drei Seiten weiter oben stand.
Oder jemand konnte sich selbst nicht mehr erinnern, wann der else Zweig 
ausgeführt wird, weil das if drei Seiten weiter oben stand oder in der 
Nacht zuvor geschrieben wurde.

von Karl H. (kbuchegg)


Lesenswert?

horst schrieb:
> Wenn der Vergleich Seiteneffekte hat, dann kommt bei zwei Vergleichen
> hintereinander nicht unbedingt das selbe Ergebnis heraus.

Das sind aber keine 2 Vergleiche hintereinander.

Entweder wird der if Teil genommen oder es wird der else Zweig genommen. 
Was anderes gibt es nicht.
Wenn aber der if-Zweig betreten wird, dann ist damit automatisch der 
else Zweig bereits aus dem Rennen, egal ob dort dann noch eine weitere 
Abfrage erfolgt oder nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Oder jemand wollte noch einmal daran erinnern, wann der else Zweig
> ausgeführt wird, weil das if drei Seiten weiter oben stand.
> Oder jemand konnte sich selbst nicht mehr erinnern, wann der else Zweig
> ausgeführt wird, weil das if drei Seiten weiter oben stand oder in der
> Nacht zuvor geschrieben wurde.

Für diese Fälle bietet C und auch C++ ein ganz raffiniertes Konstrukt:
Den Kommentar.

von Sven Scholl (Gast)


Lesenswert?

@ Stefan Ernst

switch(time)
{
   case:    //usw.
   default: //usw.
}

Das ist also nur 1 Anweisung?

Ich hatte gedacht, dass wäre schon ein Block...

Mal blöd gefragt, aber wann wird daraus ein Block?

Etwa so:

switch(time)
{
   case:    //usw.
   default: //usw.
}
i=1;

von Sven P. (Gast)


Lesenswert?

Solche saublöden Fragen entstehen immer dann, wenn man versucht, C 
anhand falscher Beispiele zu lernen, oder es halt so verkorkst 
beigebracht bekommt.

Es heißt:
1
if ( BEDINGUNG )
2
  ANWEISUNG
3
else
4
  ANWEISUNG
wobei der else-Teil wegfallen kann.

BEDINGUNG ist ein Ausdruck, ANWEISUNG eine Anweisung...son Zufall :-}

Eine Anweisung kann eines der folgenden sein:
1
AUSDRUCK ;
2
/* oder */
3
if...
4
/* oder */
5
switch...
6
/* oder for, while, do */
7
/* oder */
8
{ ANWEISUNG... }

(ja, etwas zusammengerafft)
Nun kannste dir deine If-Dinger zusammenstecken, wie LEGO-Klötze:
1
if (x)
2
  aaa();
3
else
4
  bbb();
5
  ccc();
6
7
/* äquivalent zu */
8
9
if (x) {
10
  aaa();
11
}
12
else {
13
  bbb();
14
}
15
16
ccc();

von zwieblum (Gast)


Lesenswert?

@Karl heinz Buchegger
> Das sind aber keine 2 Vergleiche hintereinander.

doch, schau mal:
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
#define I i--
5
6
void foo(int i) {
7
8
  printf("%d : ",i);
9
10
  if (I >= 10)    printf("A");
11
  else if (I < 10) printf("B");
12
13
  printf(" : %d\n",i);
14
}
15
16
int main() {
17
  foo(8);
18
  foo(9);
19
  foo(10);
20
  foo(11);
21
}

das ganze liefert :
1
 8 : B : 6
2
 9 : B : 7
3
10 : A : 9
4
11 : A : 10

das 1. conditional wird immer ausgeführt - samt seiteneffekt, das 2. nur 
dann, wenn das 1. misslingt.
das kann ganz schön böse zum debuggen sein :-)

entstehen tut der käse mesitens aus so was, wenn die grenzen plötzlich 
gleich sind und keiner den code aufräumt:
1
if (i > 10 ) tu_was_großes();
2
else if (i<5) tu_was_kleines();

von P. S. (Gast)


Lesenswert?

zwieblum schrieb:
> @Karl heinz Buchegger
>> Das sind aber keine 2 Vergleiche hintereinander.
> doch, schau mal:

Diese Argumentationsweise, bei der man das Ursprungsbeispiel so lange 
verbiegt, bis man irgendwie Recht zu haben scheint, geht mir gehoerig 
auf den Keks.

von zwieblum (Gast)


Lesenswert?

??? wieso geht's ums recht haben? das ursprungsbeispiel ist trivial, 
aber das versteckte problem nicht. nur weil's in C nicht üblich ist, 
dass vergleiche seiteneffekte haben können, heißt nicht, dass es nicht 
machbar ist. und wenn du die programmiersprache wechselst wird's sogar 
was ganz übliches ...

von horst (Gast)


Lesenswert?

Es geht auch nicht mehr um's Ursprungsbeispiel, das wurde schon geklärt.

Es geht um das zweite Beispiel von Federtier. Dort können durchaus beide 
Vergleiche (die ifs, nicht die Blöcke danach) nach einander ausgeführt 
werden.

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.