zuweisung mit Vergleichsoperator

Gast #6414111
Lesenswert?

Hallo in die Runde,

Frage zu diesem Code-Segment:
1
bool can_message_available(void)
2
{
3
  uint8_t n;
4

5
  cli();
6
  n = canix_rxq_size() > 0;
7
  sei();
8

9
  return n;
10
}

Die Zeile mit der Zuweisung an n verstehe ich nicht. Die Funktion 
canix_rxq_size() ist so definiert, dass sie ein uint8_t zurück gibt. 
Also wir dieser Rückgabewert an n zugewiesen. Aber welche Auswirkung hat 
"> 0" in dieser Zeile?

Viele Grüße, Uli
Gast #6414160
Lesenswert?

Uli schrieb:
> bool can_message_available(void)
> {
>   uint8_t n;
>
>   cli();
>   n = canix_rxq_size() > 0;
>   sei();
>
>   return n;
> }

Wer so etwas schreibt, ist doppelt blöd: erstens ist 'n' für diesen 
Zweck ziemlich ungeschickt, da denkt man automatisch an eine Zahl. 
Zweitens, und das ist eine unmittelbare Konsequenz, kommt man dadurch 
bei der Zuweisung ins Schleudern, man fragt sich sofort, ob '(n = 
canix_rxq_size()) > 0;' oder 'n = (canix_rxq_size() > 0);' gemeint ist. 
Wesentlich geschickter wäre:

bool can_message_available(void)
{
  uint8_t is_available;

  cli();
  is_available = (canix_rxq_size() > 0);
  sei();

  return is_available;
}

Das mehr an Tipparbeit rentiert sich auf lange Sicht, denn wenn man ein 
paar Wochen später noch mal dahin schaut, muss man bei der urspr. 
Variante selbst erst man überlegen, was für einen Murks man da 
angerichtet hat.
Gast #6414183
Lesenswert?

es sei noch angemerkt, dass der Typ bool ja existiert und durchaus für n 
oder is_available verwendet werden kann.

Selbst wenn das nicht so performant sein mag, weil bool 16 oder 32 Bit 
ist. Wenn man es nicht gemessen hat, ist es zweifelhaft, dass es 
langsamer ist. Und wenn man es gemessen hat, sollte man das im Kommentar 
berücksichtigen (Achtung: uint8_t weil es 4 Takte länger sind in der 
Version 1.0 des Kompilers und die Routine pro Sekunde 11 mal aufgarufen 
wird!)
Moderator Persönliche Seite #6414348
Lesenswert?

Uli schrieb:
> Es ist mir jetzt klar, allerdings war die Schreibweise für mich eher
> unübersichtlich.

Diese Schreibweise hätte den gleichen Effekt:
1
    if (canix_rxq_size() > 0)
2
    {
3
        n = 1;
4
    }
5
    else
6
    {
7
        n = 0;
8
    }

Wenn Du das lesbarer findest (ich persönlich sehe das so), dann benutze 
das. Der resultierende Assembler-Code dürfte derselbe sein.

P.S.
Ähnlich sähe es aus, wenn man n wirklich als Bool definiert, welches ja 
auch der Typ des Rückgabewertes der Funktion ist. Hier könnte man dann 0 
und 1 durch die entsprechenden Wahrheitswerte austauschen.
Gast #6414433
Lesenswert?

A. B. schrieb:
> Zweitens, und das ist eine unmittelbare Konsequenz, kommt man dadurch
> bei der Zuweisung ins Schleudern, man fragt sich sofort, ob '(n =
> canix_rxq_size()) > 0;' oder 'n = (canix_rxq_size() > 0);' gemeint ist.
Was sollte denn
(n = canix_rxq_size()) > 0;
bewirken? Dann hätte man einen Vergleich, dessen Ergebnis nicht 
ausgewertet wird. Damit wäre der Vergleich unsinnig.

Persönlich mag ich diese Schreibweise, weil sie so schön 
Nerd/Hacker-mäßig aussieht, aber in der praktischen Anwendung würde ich 
die nicht empfehlen.
Gast #6414472
Lesenswert?

Teo D. schrieb:
> Was spricht eigentlich gegen
> n = (bool) canix_rxq_size();

Es muss nicht sein, dass bool binär ist. Es kann auch ein int oder uint8 
oder sonstwas in einer C-Version ohne bool sein und liefert dann nicht 0 
oder 1 zurück.

Alternativ (wenn ggf negativ auch true ist)
n=!!canix_rxq_size();
Persönliche Seite #6414876
Lesenswert?

Uli schrieb:
> Es ist mir jetzt klar, allerdings war die
> Schreibweise für mich eher unübersichtlich.

Rechts vom "=" steht ein Ausdruck, und dessen Wert wird n zugewiesen.

Ob das unübersichtlich ist, ist eine Frage der Gewohnheit.  Ich 
persönlich bevorzuge die platzsparende Alternative gegenüber dem 
länglichen if-else.

Sinnvoller als der Einsatz wie im Beispiel ist bei komplexeren Abfragen 
wie
1
    uint8_t n = (a > 1) + (b > 2) + (c > 3);
2
    switch (n)
3
    {
4
        case 2:
5
            // Mindestens 2 Bedingungen sind erfüllt.
6
            ...
7
    }
In dem Fall sind Klammern um die Bedingungen erforderlich.

Bei einer einzigen Bedingung Klammern für bessere Übersichtlichkeit zu 
setzen kann man machen; aber wie oben mangelnde Sprachkenntnis als 
Begründung für Klammersetzung anzuführen ist einer der schlechtesten 
Argumente überhaupt.

Und ob man bei meinem Beispiel über eine Zwischenvariable geht oder
1
switch ((a > 1) + (b > 2) + (c > 3))
verwendet, ist natürlich dem Coding Style überlassen.

Wenn die Bedingungen komplexer sind, kann man auch auf mehrere Zeilen 
aufteilen:
1
    uint8_t n_conditions = 0;
2
    n += bedingung_1 (wert1 + wert2 * wert3);
3
    n += bedingung_2 (wert3 + wert4 - wert5);
4
    n += bedingung_3 (wert1 * wert2 * wert4);
5
    switch (n) ...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren