phpbar.de logo

Mailinglisten-Archive

[php] goto statements

[php] goto statements

Johannes Schlueter schlueter at phpbar.de
Sam Jul 31 17:33:52 CEST 2004


Hi,

On Saturday 31 July 2004 16:43, Reinhold Jordan wrote:
> naja, nur weil es geht, heißt es ja nicht, daß es auch
> benutzt wird. In C/C++ gibt es auch ein goto - aber in
> den letzten 16 Jahren habe ich nur ein Programm gesehen,
> wo es auch benutzt wurde. Und de Menschen, der das
> verbockt hat, würde ich kaum als Programmierer
> bezeichnen...

In meinem aktuellen Linux-Kernel-Source (2.6.5 + Gentoo-patches) habe ich 
26426 mal das Pattern /goto [a-b_]+;/ innerhalb von .c Dateien gefunden.[^1]

Wie ich schon schrieb  setzt man goto zum Error-Handling ein. Damit ich mir 
hier jetzt kein (schlechtes) Beispiel erfinden muss mal ein Ausschnitt aus 
dem Linux-Kernel, genauer sound/usb/usbaudio.c (per Zufall ausgewählt, ein 
wenig gekürzt und ein wenig Einrückung entfernt, damit die Zeilen nicht zu 
lang werden)

/*
 * set up and start data/sync urbs
 */
static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
{
        unsigned int i;
        int err;

        for (i = 0; i < subs->nurbs; i++) {
            snd_assert(subs->dataurb[i].urb, return -EINVAL);
            if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
              snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
              goto __error;
            }
        }
       if (subs->syncpipe) {
         for (i = 0; i < SYNC_URBS; i++) {
           snd_assert(subs->syncurb[i].urb, return -EINVAL);
           if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb)
              < 0) {
             snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
             goto __error;
           }
          }
       }
/*...*/
        return 0;

 __error:
        // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
        deactivate_urbs(subs, 0, 0);
        return -EPIPE;
}

Nun was macht er? Spielt an seinen Substreams rum und wenn ein Fehler 
passiert, was an mehreren Stellen passieren kann, springt er mit goto ans 
Ende der Funktion und räumt auf. Was wären die Alternativen?
  - Den Aufräumcode in jede Stelle räumen wo es schief laufen kann und mit 
"return -EPIPE" aus der Funktion raus gehen
  - Eine Funktion raeum_auf() bauen und die Aufräum-Logik da rein und in 
komplexeren Situationen als oben alle Zeiger übergeben um den Speicher wieder 
freizugeben
  - Ein do { ... } while(0) Konstrukt bei dem im Fehlerfall ein break rausgeht 
und ansosnten am Ende des do-Blocks ein return 0 steht verwenden.

Alles wohl nicht so schön und klar wie das goto - wenn es richtig verwendet 
wird. 

Nach dem Ausflug in die C-Welt zurück bei PHP ist dies weit weniger notwendig, 
da PHP den meisten Müll selber aufräumt (Stichwort: garbage collection) aber 
gelegentlich ist eigener Aufräumcode was schönes.

Nun hat PHP5 Exceptions, mit denen kann man das auch machen, bloß wenn man mit 
PHP Prozedural programmiert - was ja durchaus erlaubt ist und immer mal 
wieder Sinn macht - ist es doch etwas fraglich für's Error-Handling plötzlich 
auf OO-Paradigmen zu setzen.

Soweit mein Senf dazu,
johannes

[^1] Bevor es jetzt heißt "Jaja die Linux-Leute können eh nichts": Auch in dem 
Teil des Win2k-Sources der Microsoft abhanden gekommen ist gibt es Gotos...
-- 
Johannes Schlüter
php::bar | Der Treffpunkt für Einsteiger und Profis   http://www.phpbar.de

php::bar PHP Wiki   -   Listenarchive