Rückgabewerte von Funktionen beim Erfolg / Fehler

Gast #6170417
Lesenswert?

Hallo,

gibt es so etwas wie eine Vorschrift oder eine Regel für bestimmte 
Rückgabewerte von Funktionen bei einer erfolgreichen / fehlerhaften 
Ausführung?

Die main-Methode liefert ja im Erfolgsfall eine 0 (EXIT_SUCCESS) zurück 
(und eine 1 (EXIT_FAILURE) falls etwas schief läuft). Das braucht wohl 
das Betriebssystem.

Und diese Festlegung (return 0 == keine Fehler und return 1 == Fehler) 
wird anscheinend auch bei anderen Funktionen benutzt.
1
if(rename(oldname, newname)!=0){
2
 //error
3
}
Aber warum? Die if-Bedingung würde doch besser und logischer aussehen, 
wenn man diese Zahlen vertauscht (return 0 = keine Fehler, return 1 == 
Fehler).
1
if(!rename(oldname, newname)){
2
 //error
3
}
4

5
if(!delete(my_file)){
6
 //error
7
}
Also quasi die Rückgabewerte als bool-Werte betrachten (1 == true == 
alles in Ordnung, 0 == false == Fehler).
Gast #6170434
Lesenswert?

Eine nicht uninteressante Frage, auf die ich auf die Schnelle auch keine 
Antwort im Netz finden konnte, Vermutlich wird man aber beim Studium 
sehr früher OS Dokumentationen Unix, BSD, CP/M etc. möglicherweise auf 
eine Erklärung stossen.

Bis dahin würde ich mir das so erklären:

Angenommen, es wäre so, wie Du vorschlägst. Also:

> return 0; ----> Fehler
> return 1; ----> kein Fehler

und ich will die Fehler detailliert unterscheiden können, dann ergäbe 
sich zusätzlich (das sind jetzt nur so Hausnummern):

2 --- falsche Eingabe
3 --- Underflow
4 --- Out of memory
etcpp.

also folgende Bereiche:
1 ist kein Fehler
aber 0 und {2, 3, ..., n} ---> Fehler

Der Test
1
if (!errorcode) { ... }

würde also nicht immer dann wahr sein, falls kein Fehler aufgetreten 
ist.

Man könnte noch fragen, ob es nicht anders herum, mehrere Möglichkeiten 
des Erfolgs gibt, aber das kompliziert die Sache nur (je nachdem man das 
für kompliziert hält), weil man dann das Unterschreiten (oder 
Überschreiten) einer Schwelle testen müsste.

So also kann ich mit
1
if (!errorcode) { ... }

falls, das Ergebnis wahr ist, grundsätzlich davon ausgehen das alles 
OK ist. Andernfall muss (oder kann ich wenigsten) die Fehler 
differenzieren; was ich, wie ich oben unterstellte, bei Erfolg nicht tun 
will. Es gibt vielleicht in einigen Fällen mehrere Möglichkeiten des 
Erfolgs, aber die werden dann einfach erledigt (die Erfolge) und ich 
will hinterher garnicht wissen, was genau den Erfolg ausgemacht wird 
bzw. ich erkenne das an ganz anderen Dingen (Datei wurde erzeugt, Inhalt 
ist wie erwartet, Gerät tut was ich will).

Das ist nur eine Erklärung der bestehenden Situation, keine darüber, was 
sich die ersten Entwickler so dabei gedacht haben, Aber ich vermute, sie 
wird ziemlich gut passen.
#6170442
Lesenswert?

Theor schrieb:
> Ein Hinweis noch. Es gibt tatsächlich Systeme, die das etwas
> anders machen und auch Erfolge differenzieren (können)

Dann gibt es noch so Systeme, die unspezifisch "Fehler" zurückgeben und 
dann erwarten, dass man eine bestimmte Funktion (z.B. GetLastError, 
SDL_GetError) aufruft oder eine bestimmte Variable (errno) untersucht, 
um die genaue Ursache herauszufinden. Solche Systeme sind unpraktisch, 
weil sie ohne weiteres nicht thread-safe sind.

Und dann gibt es noch Verfahren, die nicht zuverlässig zwischen Erfolgen 
und Fehlern unterscheiden können, z.B. liefert atoi() im Fehlerfall -1 
zurück, was aber auch einen Erfolg kennzeichnen kann. Solche Systeme 
sind große Scheiße.

In moderneren Programmiersprachen gibt es häufig die Möglichkeit 
mehrerer Rückgabewerte und dort bekommt man dann oft einen Vektor 
[Status, Rückgabewert] zurück.

Aber in C ist "0 ist Erfolg" eine weit verbreitete Konvention, gerade 
weil sie verschiedene Fehlerfälle ohne Aufwand unterscheiden kann.
Gast #6170502
Lesenswert?

Wenn Du keinen Rückgabewert brauchst, ist bool gut (0 ist schlecht, 
alles andere gut)

Wenn Du echte, positive Rückgabewerte brauchst, ist 0, <0 oder <=0 als 
Fehler gut.

Bei Pointern ist es meistens 0=Fehler.

Wenn Du keinen Rückgabewert brauchst, aber dem Benutzer Fehlerhinweise 
geben willst, dann ist 0 für OK gut: es gibt nicht DEN Grund, warum 
etwas funktioniert, aber einen ersten (oder wichtigsten), warum etwas 
nicht funktioniert.

Für embedded sollte man m.E. nur OK/nicht OK zurück liefern, wenn es 
keinen Benutzer gibt, der direkt eingreift. Die Fehlerinfos gehören 
stattdessen in irgendeiner Weise geloggt, gezählt, gespeichert. Sonst 
wird jeder Aufruf (Einzeiler) von 30 Zeilen was ist wenn zugemüllt.
Gast #6170508
Lesenswert?

A. S. schrieb:
> Die Fehlerinfos gehören
> stattdessen in irgendeiner Weise geloggt, gezählt, gespeichert. Sonst
> wird jeder Aufruf (Einzeiler) von 30 Zeilen was ist wenn zugemüllt.

Warum?

Fehlerfrei = 0

Fehler <> 0, ob der Grund für den Fehler interessiert und dekodiert 
werden muss, hängt vom Aufrufer ab. Die "30 Zeilen" sind also nur 
notwendig, wenn die Fehlerursache ermittelt werden muss und können auch 
in eine Funktion gepackt werden.
Beitrag #6170511 wurde von einem Moderator gelöscht.
#6170518
Lesenswert?

Moin,

Jetzt hab' ich natuerlich nicht in alle diese Files reingeguckt, geh' 
aber mal stark davon aus, dass die alle voll bis unters Dach sind mit 
faulen Ausreden warum irgendwas (mutmasslich ein Funktionsaufruf) nicht 
funktioniert hat...
Wenn was funktioniert hat, interessierts erfahrungsgemaess keine Sau, 
warum. Es hat ja funktioniert.
1
wk [ ~ ]$ find /usr/include/ -name "*errno*"
2
/usr/include/apr-1/apu_errno.h
3
/usr/include/apr-1/apr_errno.h
4
/usr/include/octave-4.4.1/octave/oct-errno.h
5
/usr/include/bits/errno.h
6
/usr/include/CLucene/ext/boost/exception/errinfo_errno.hpp
7
/usr/include/boost/cerrno.hpp
8
/usr/include/boost/compatibility/cpp_c_headers/cerrno
9
/usr/include/boost/geometry/srs/projections/impl/pj_strerrno.hpp
10
/usr/include/boost/exception/errinfo_errno.hpp
11
/usr/include/gsl/gsl_errno.h
12
/usr/include/ghostscript/errno_.h
13
/usr/include/uv/errno.h
14
/usr/include/schily/errno.h
15
/usr/include/asm-generic/errno-base.h
16
/usr/include/asm-generic/errno.h
17
/usr/include/node/uv-errno.h
18
/usr/include/linux/errno.h
19
/usr/include/sys/errno.h
20
/usr/include/c++/8.2.0/cerrno
21
/usr/include/errno.h
22
/usr/include/asm/errno.h
23
/usr/include/libnl3/netlink/errno.h
24
wk [ ~ ]$

Gruss
WK
Gast #6171464
Lesenswert?

Da gibt es keine GESETZE.

Aber sinnvolle und weniger schlaue Verhaltensregeln:

Bei kleinen Aufgaben ist der Rückgabewert direkt brauchbar:
- Welche Taste wurde gedrückt?
- Wieviele ms hat es gedauert?
- Der Rückgabewert Null = 0 wäre dann kein Fehler-Code, sondern
  hieße nur: Da kam nix, da war nix...

Bei komplexeren Funktionen ist eher interessant, ob sie
fehlerfrei abliefen (Error = 0), oder weshalb es nicht geklappt
hat.

ERROR = 0 = OK = OHNE PROBLEM ist sehr sinnvoll:
Wenn es gut gelaufen ist, will keiner wissen, warum!

ERROR != 0, (oder <> 0,) bedeutet: Da liegt ein Problem vor.
- Und wenn der Programmierer sich Mühe gegeben hat, ist der
Error-Code vielleicht eine Hilfe zur künftigen Fehlervermeidung!
#6171475
Lesenswert?

zitter_ned_aso schrieb:
> gibt es so etwas wie eine Vorschrift oder eine Regel für bestimmte
> Rückgabewerte von Funktionen bei einer erfolgreichen / fehlerhaften
> Ausführung?

So um 1975 herum hat Digital Equipment festgelegt, wie Rückgabewerte 
auszusehen haben (für VMS). Weil früher alles viel besser war, ist die 
Vorschrift ein wenig umfangreicher geworden, 6 Seiten im Handbuch¹ (bzw. 
35, wenn man Exceptions dazu zählt). Die Vorschrift gilt heute noch und 
wurde von Microsoft für NT leicht modifiziert übernommen:

Theor schrieb:
> Ein Hinweis noch. Es gibt tatsächlich Systeme, die das etwas anders
> machen und auch Erfolge differenzieren (können): Etwa
> https://en.wikipedia.org/wiki/HRESULT


1) 
https://support.hpe.com/hpesc/public/docDisplay?docId=emr_na-c04621389
Angehängte Dateien:
Gast #6171488
Lesenswert?

Eine Vorschrift oder gar Standard gibt es meines Wissens nicht. Das 
kommt immer darauf an, wie eine API/Library das per Konvention umsetzt. 
Da C keine Ausnahmen oder ähnliches kennt, behilft man sich oft mit 
Rückgabecodes. Bei Vulkan z.B. ist es VkResult (eine simple Enumeration) 
oder bei Microsofts COM das HRESULT (ein strukturierter 32-bit 
Ganzzahl-Fehlercode). Das Prinzip ist i.d.R. immer das gleiche: Ein Wert 
von 0 zeigt den Erfolg an, jeder andere Wert einen Fehler, den man 
entweder als positiven oder negativen Integerwert ablesen kann. Einige 
alte Windows APIs geben auch "bool" (hier ein 32-bit Integer) zurück, 
tritt dort ein Fehler auf kann man dann mit GetLastError() den damit 
verbundenen Fehlercode für den aktuellen Thread abrufen. Warum "0" als 
Erfolgsmeldung? Weil es die Bedingung einfacher macht. Man muss so nur 
auf "0" prüfen, ob etwas schief gelaufen ist, völlig egal was der Fehler 
war.

Da so eine Funktion nicht direkt einen Wert zurückgeben kann, werden 
diese meist als letzter Paramter mit einem Pointer-to-Pointer übergeben.
#6171492
Lesenswert?

Die klassischen Unix System-APIs verwenden folgende Konvention:

0: Erfolgreich
-1: Fehler

Für Calls die einen Wert zurückgeben:

>= 0: Gültiger Wert
-1: Fehler

Der eigentliche Fehlercode steht in errno.

In seltenen Fällen, wenn auch negative Werte gültige Rückgabewerte sind, 
zählt nur errno. Dabei muss der Programmierer errno vor dem 
Funktionsaufruf selber zurück setzen:
1
errno = 0;
2
result = systemcall();
3
if(errno) {
4
    perror(NULL);
5
    exit(EXIT_FAILURE);
6
}

Die klassischen Unix Library-APIs halten sich meist an eine ähnliche 
Konvention:

-1 oder NULL-Pointer: Fehler
>=0 oder !NULL: Erfolgreich

Da mittlerweile eine ganze Reihe von Bastlern an den Linux-Libraries 
tätig waren löst sich diese Konvention langsam auf.
Gast #6171494
Lesenswert?

> So um 1975 herum hat Digital Equipment festgelegt ...
Very interesting, but 45 years ago...

>  zitter_ned_aso (Gast)
wollte aber wohl eher wissen, wie sie/er da selbst
erfolgsversprechend rangeht.

Da ist weniger ein 35-seitiges Pamphlet für Juristen gefragt,
sondern eher eine grundsätzlich einleuchtende Vorgehensweise.

Sinnfällige (!) Regeln sind erfahrungsgemäß für logisch denkende
IT-ler und Techniker leichter einzuhalten, als sich das logik-
ferne Fakultäten vorstellen können.

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