In einem anderen Thread ist wiedermal aufgekommen dass goto von grund auf böse und nicht zu verwenden ist. Ich weiß nicht ob das ernst gemeint war, oder ob das nur dazu diente einem Anfänger das goto abzugewöhnen.
Auf jeden Fall stelle ich die Behauptung auf, dass es in C zwei Anwendungsfälle, und in C++ einen Anwendungsfall gibt, wo goto unentbehrlich ist.
Der erste Anwendungsfall ist ziemlich eindeutig: herausspringen aus verschachtelten schleifen.
Das gilt für C gleichermaßen wie für C++.
Code: Alles auswählen
#include <stdio.h>
int main()
{
int uninitialized[90][60][90];
int i, j, k;
for (i = 0; i < 90; i++)
for (j = 0; j < 60; i++)
for (k = 0; k < 90; i++)
{
if (uninitialized[i][j][k] == 1337)
{
printf("That's too l33t for me! I have to get out!\n");
goto rescue_point;
}
}
printf ("Everything went fine.\n");
rescue_point:
printf("We are safe again.\n");
return 0;
}
Der zweite Anwendungsfall ist ein wenig komplizierter:
Fordert eine Funktion mehrere Ressourcen an, von denen jede Anforderung fehlschlagen kann, und gibt es auch danach Möglichkeiten für Fehler in denen die Funktion abbrechen muss, so ist es schwierig oder zumindest sehr umständlich an jedem Punkt an dem die Funktion abbrechen kann die Ressourcen wieder freizugeben.
Ein Goto erleichtert hier vieles. Hier mal ein "etwas überspitzter" code, der allerdings die problematik ungefähr darstellen soll:
Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int CATASTROPHAL_ERROR = 0x666;
const int ALOTOFSPACE = 0x100;
#define DO_STUFF()
int functionThatCanFail()
{
return rand() % 2;
}
static int resourceFunctionWorking;
void functionWithALotOfResources()
{
char* uselessbuffer = NULL;
char* sometext = NULL;
FILE* bigfile = NULL;
resourceFunctionWorking = 1;
uselessbuffer = malloc(ALOTOFSPACE * sizeof(char));
if (uselessbuffer == NULL)
{
printf("Failed to allocate space. Bailing out.\n");
return;
}
sometext = malloc(ALOTOFSPACE * sizeof(char));
if (sometext == NULL)
{
printf("Failed to allocate space. Bailing out.\n");
return;
}
if (!functionThatCanFail())
{
printf("Function failed. Bailing out.\n");
return;
}
bigfile = fopen("filethatdoesntexist.txt", "r");
if (bigfile == NULL)
{
perror("Failed to open file");
return;
}
DO_STUFF();
free(uselessbuffer);
free(sometext);
fclose(bigfile);
resourceFunctionWorking = 0;
}
int main()
{
srand(time(NULL));
functionWithALotOfResources();
if (resourceFunctionWorking)
{
printf("Help! I'm confused! What went wrong? Bailing out...\n");
exit(CATASTROPHAL_ERROR);
}
return 0;
}
Die Lösung ist entweder: in jedem einzelnen if (fehlschlag){} block alle ressourcen zu überprüfen, und sie dann freizugeben ODER ein kleines goto. Ich finde diese Möglichkeit ist um einiges Eleganter. Der Code der veränderten functionWithALotOfResources() funktion sieht so aus:
Code: Alles auswählen
void functionWithALotOfResources()
{
char* uselessbuffer = NULL;
char* sometext = NULL;
FILE* bigfile = NULL;
resourceFunctionWorking = 1;
uselessbuffer = malloc(ALOTOFSPACE * sizeof(char));
if (uselessbuffer == NULL)
{
printf("Failed to allocate space. Bailing out.\n");
goto exit_point;
}
sometext = malloc(ALOTOFSPACE * sizeof(char));
if (sometext == NULL)
{
printf("Failed to allocate space. Bailing out.\n");
goto exit_point;
}
if (!functionThatCanFail())
{
printf("Function failed. Bailing out.\n");
goto exit_point;
}
bigfile = fopen("filethatdoesntexist.txt", "r");
if (bigfile == NULL)
{
perror("Failed to open file");
goto exit_point;
}
DO_STUFF();
exit_point:
if (uselessbuffer)
free(uselessbuffer);
if (uselessbuffer)
free(sometext);
if(bigfile)
fclose(bigfile);
resourceFunctionWorking = 0;
}
Ich bin gespannt auf Gegenargumente. Ich finde allerdings man sollte eine MÖGLICHKEIT einer Sprache nicht von vornherein verteufeln, sondern sich darüber im klaren sein, dass es immer wege gibt in der man sie einsetzen kann.
Um diese Nachricht zu verbreiten hätte ich gerne einen Eintrag in der FAQ, mit dem Titel "goto und wie man es verhindern kann", das zwar auf die Gefahren und Probleme des "klassischen" gebrauchs von goto eingeht, allerdings eben auch auf die Probleme die ohne es nicht lösbar sind.
Zum Abschluss möchte ich noch einen kleinen Comic von Randell Munroe, aus seiner wunderbaren Seite xkcd.com einfügen, der ein bisschen die Furcht vor dem goto parodiert:
request for comments
mfg, fat-lobyte