[linux-l] RS-232 oder USB lesen mit (Schauder...) Java Os-unabhaengig

Oliver Bandel oliver at first.in-berlin.de
Fr Sep 30 00:47:42 CEST 2005


On Thu, Sep 29, 2005 at 05:39:24PM +0200, Jan-Benedict Glaw wrote:
> On Thu, 2005-09-29 17:13:16 +0200, Oliver Bandel <oliver at first.in-berlin.de> wrote:
> > Was aber, wenn zur Laufzeit ein Fall auftritt, der nicht
> > abgefragt wird in dem Code?
> >  (weder explizit, noch mit Wildcard-match?!)
> 
> ...dann hat der Programmierer enums nicht verstanden.


...oder sich einfach nur vertippt.
Sowas soll ja vorkommen...




> 
> > ========================================================
> > # type my_type = Blah | Blih | Blubb | Untested_case;;
> > type my_type = Blah | Blih | Blubb | Untested_case
> > # let say_something x = match x with
> >     Blah -> "Blah"
> >    |Blih -> "Dies ist der Blih"
> >    |Blubb -> "Blubber-Hannes";;
> > Warning: this pattern-matching is not exhaustive.
> > Here is an example of a value that is not matched:
> > Untested_case
> > val say_something : my_type -> string = <fun>
> > # say_something Blih;;
> > - : string = "Dies ist der Blih"
> > # say_something Untested_case;;
> > Exception: Match_failure ("", 1, 22).
> > # 
> > ========================================================
> > 
> > Welche Exception wirft C bzw. gcc in dem Falle?
> 
> Keine, ist nicht seine Aufgabe. enums werden zur compile time
> ausgewertet, nicht hinterher (-> das ist viel zu langsam :-)

Die werden aber zur Laufzeit ausgeführt.

Dies ist ein klassischer Fehler, der auftreten kann.

Die Value, die in den switch geht, ist nicht von dem Enum-Typ abgedeckt,
den man checken will. Und schon hat man ein Problem, eines das einem
möglicherweise erst sehr spät auffällt, weil der switch-case nur zu
seltsamem Verhalten führt, und nicht gleich zu einem Absturz
(des Programms). Der Absturz (des Flugzeugs) wird früher oder später
schon noch kommen... keine Sorge. :->



> 
> > Wenn "default" vergessen wurde, fliegt Dir der C-Code
> > möglicherweise um die Ohren!
> 
> Bei enums sollte man keinen default benutzen.

Warum nicht?
default könnte vergessene Cases abfangen.
Wenn man auf diese selbst eingebaute Möglichkeit einer "Exception"
verzichtet, macht man das Problem nur noch schlimmer.



Nimm diesen hier:

/* ------------------------------------------------------------ */
#include <stdio.h>


enum blah { FOO, BAR, BAZ };
enum schnulli { ICKE, DETTE, KIEKE, MAL };

void
check_this (enum blah enum_to_check)
{
        switch (enum_to_check) {
                case FOO:
                        printf ("foo\n");
                        break;
                case BAZ:
                case BAR:
                        printf ("bar\n");
        }
        return;
}

int main()
{
  check_this(MAL);
  return 0;
}

/* ------------------------------------------------------------ */

Auch mit "-Wall" und "-pedantic" sagt der Compiler nix...
...sind zwar alle blah-enums abgecheckt, aber daß da ein
enum "schnulli" als Argument übergeben wird, ist ihm egal...


...auch beliebige Zahlenwerte lann man übergeben.

Kein Problem: der Compiler meckert nicht.

Wieso Du bei solchen Verhalten auch noch auf den "default"-Case verzichten
willst, ist mir unbegreiflich.
Wenn Du dann noch behaupten willst, das sei sichere Programmierung,
dann gute Nacht. :(

Wenigstens ein fprintf nach stderr mit einem exit sollte man da einbauen,
dann merkt man, wenn man Mist gebaut hat, und wo es knirschte!

Also so:
========




/* ------------------------------------------------------------ */
include <stdio.h>
#include <stdlib.h>                                                                                                       


enum blah { FOO, BAR, BAZ };
enum schnulli { ICKE, DETTE, KIEKE, MAL };

void
check_this (enum blah enum_to_check)
{
        switch (enum_to_check) {
                case FOO:
                        printf ("foo\n");
                        break;
                case BAZ:
                case BAR:
                        printf ("bar\n");
                default: fprintf( stderr, "hard programming error! BUG! file: %s line: %d\n", __FILE__, __LINE__);
                          exit(EXIT_FAILURE);
        }
        return;
}

int main()
{
  check_this(5);
  return 0;
}

/* ------------------------------------------------------------ */


Gibt dann wenigstens:

==========================================================
first:~/Trans oliver$ ./a.out 
hard programming error! BUG! file: foo.c line: 18
first:~/Trans oliver$ 
==========================================================

Mit so einem printout kann man wenigstens was anfangen.
Dann hat man auch noch eine Chance, in der Testphase
Fehler auszumerzen.

Aber ich weiß ja: "es dauert zu lange" den default-case
und das fprintf zu tippen.
Könnte ja ein paar Minuten dauern...

...dann nimmt man lieber ein paar Wochen debugging-Zeit in kauf und das Risiko,
den Fehler garnicht mehr zu finden... :(



> Für offene Variablen,
> denen jeglicher Mist zugewiesen sein könnte, ist das schon eher
> sinnvoll.


Ein default-case in einem switch-/case-Konstrukt in C ist IMMER sinnvoll!
Und man schreibt ihn am besten auch als erstes hin.

Ciao,
   Oliver



Mehr Informationen über die Mailingliste linux-l