Hallo zusammen,
ich habe (mal wieder) eine vermutlich total einfache Frage zu gutem
C-Stil: Welches ist eigentlich der richtige Datentyp für Rückgabewerte,
wenn diese nur Fehlerzustände signalisieren sollen (also normalerweise
0)?
Beispiel wie es tausendfach vorkommt:
1
uint8_tfunctionThatMayFail(void){
2
// do something
3
if(allesinordnung){
4
// ...
5
returnEXIT_SUCCESS;
6
}
7
else{
8
returnEXIT_FAILURE;
9
}
10
}
Wie man sieht, nutze ich aus AVR-Gewohnheiten uint8_t, weil der fuer
alle Fehlerzustände ausreicht (wer will schon mehr als 255
Fehlermeldungen in einer Funktion schreiben?). Die meisten
Standardfunktionen nutzen wohl int, desgleichen in meinen C-Büchern und
ich vermute, das geschieht aus traditionellen Gründen.
Welchen Datentyp nutzt man denn für guten Stil? Gibt es da etwas
Vordefiniertes? Es böte sich ja ein enum-Typ an.
Viele Grüße
W.T.
Walter Tarpan schrieb:> Welchen Datentyp nutzt man denn für guten Stil?
bool?
(#include <stdbool.h>, damit du ihn auch bei C bekommst, nicht nur
bei C++.)
Walter Tarpan schrieb:> Wie man sieht, nutze ich aus AVR-Gewohnheiten uint8_t, weil der fuer> alle Fehlerzustände ausreicht (wer will schon mehr als 255> Fehlermeldungen in einer Funktion schreiben?). Die meisten> Standardfunktionen nutzen wohl int, desgleichen in meinen C-Büchern und> ich vermute, das geschieht aus traditionellen Gründen.
Nicht nur.
int kann von einem Compiler immer effizient verarbeitet werden. char
oder Dein uint8_t (unsigned char) eben nicht überall. Bei x86 kannst Du
direkt mit 8 Bit Registern arbeiten, ARM oder MIPS können das nicht. Da
gibt es kein add al,bl und add ax,bx und add eax,ebx, sondern nur ein
add r1,r2; wobei r1 und r2 immer ganze Register sind. Wenn dann als
Ergebnis explizit ein 8 Bit Wert gefordert ist, brauchst Du noch das
Äquivalent zu einem and r1,#255 hinterher.
Daher eben int.
> Welchen Datentyp nutzt man denn für guten Stil? Gibt es da etwas> Vordefiniertes? Es böte sich ja ein enum-Typ an.
... der intern wieder ein int ist.
Wenn Du nur Wahrheitswerte zurückgeben willst, dann mach es doch. bool
existiert (mit stdbool.h), und dann weiß jeder, dass er nur ein true
oder false zu erwarten hat.
fchk
Frank K. schrieb:> int kann von einem Compiler immer effizient verarbeitet werden.
Solange man nicht auf einem 8-Bit-Prozessor arbeitet. Dort ist int für
den Compiler eher umständlich zu handhaben.
Frank K. schrieb:> Da gibt es kein add al,bl und add ax,bx und add eax,ebx, sondern nur ein> add r1,r2; wobei r1 und r2 immer ganze Register sind. Wenn dann als> Ergebnis explizit ein 8 Bit Wert gefordert ist, brauchst Du noch das> Äquivalent zu einem and r1,#255 hinterher.
Nun rechnet man aber mit Fehlercodes in der Regel nicht, sondern setzt
sie nur und vergleicht sie. Dazu muß nirgends irgendein Ergebnis auf 8
Bit beschnitten werden.
Danke für die Antworten.
Schade, ich hatte gehofft, daß die Antwort in etwa lautet wie:
"Mööönsch, genau dafür gibt es doch 'return_t', was hast Du für
schlechte Bücher?"
Aber offensichtlich gehen da sogar die Meinungen der Experten
auseinander.
Peter Dannegger schrieb:> uint_fast8_tJörg Wunsch schrieb:> bool?
Irgendetwas, was zu uint_fast8_t ausgedrückt wird war mir auch
vorgeschwebt. Bool ist mir doch etwas zu wenig. Zumindest meine
Test-Routinen werten die Rückgabewerte etwas detaillierter aus, um
sinnvolle Fehlermeldungen zu werfen.
Rolf Magnus schrieb:> Nun rechnet man aber mit Fehlercodes in der Regel nicht, sondern setzt> sie nur und vergleicht sie. Dazu muß nirgends irgendein Ergebnis auf 8> Bit beschnitten werden.
Also ich gehöre auch zu den Leuten, denen die Rechenaufwand-Effizienz
bei Fehlermeldungen total egal ist - zumindest sobald sie ungleich Null
sind. Und in diesem Fall ist mir wichtiger, eine möglichst genaue
Meldung zu bekommen, da das System danach ohnehin in einem sicheren
Zustand sein Dasein in einer Endlosschleife fristet. Für "gracefull
degradation" sind meine Anwendungen aber auch noch zu einfach.
Aber Fehlerbehandlung ist für mich eh noch etwas Rätselhaftes. Alle
C-Bücher und Tutorials und Application Notes, die ich mir bislang
durchgearbeitet habe beschränken sich darauf, für die Fehlerbehandlung
etwas wie
1
if(error){
2
// Hier Fehlerbehandlung reintun
3
}
, wobei sich kaum jemand die Mühe macht zu beschreiben, wie eine
sinnvolle Fehlerbehandlungsroutine überhaupt aussieht.
Danke für die Diskussion!
W.T.
Rolf Magnus schrieb:>> int kann von einem Compiler immer effizient verarbeitet werden.>> Solange man nicht auf einem 8-Bit-Prozessor arbeitet. Dort ist int für> den Compiler eher umständlich zu handhaben.
... was zeigt, dass C ursprünglich nicht auf einer 8 Bit Maschine
entstanden ist. Du wirst im Standard viele Stellen finden, wo von dieser
Annahme ausgegangen wird.
>> Da gibt es kein add al,bl und add ax,bx und add eax,ebx, sondern nur ein>> add r1,r2; wobei r1 und r2 immer ganze Register sind. Wenn dann als>> Ergebnis explizit ein 8 Bit Wert gefordert ist, brauchst Du noch das>> Äquivalent zu einem and r1,#255 hinterher.>> Nun rechnet man aber mit Fehlercodes in der Regel nicht, sondern setzt> sie nur und vergleicht sie. Dazu muß nirgends irgendein Ergebnis auf 8> Bit beschnitten werden.
Das weiß der Compiler aber nicht, und das steht auch nicht so im
Standard.
fchk
Walter Tarpan schrieb:> Aber Fehlerbehandlung ist für mich eh noch etwas Rätselhaftes.
Entweder ein enum oder ein passender Integer-Typ und dann mit #define
gegebene Rückgabecodes. Eine andere Methode, die auch von manchen APIs
verwendet wird, ist eine Rückgabe, die nur sagt "fehler" oder "ok" und
dann ein getError() oder so, das im Fehlerfall einen Fehlercode der
letzen Aktion zurückgibt. In Standard-C gibt sowas - leider aber nicht
als Funktion - ja auch, in Form von errno.
Frank K. schrieb:> Rolf Magnus schrieb:>>>> int kann von einem Compiler immer effizient verarbeitet werden.>>>> Solange man nicht auf einem 8-Bit-Prozessor arbeitet. Dort ist int für>> den Compiler eher umständlich zu handhaben.>> ... was zeigt, dass C ursprünglich nicht auf einer 8 Bit Maschine> entstanden ist. Du wirst im Standard viele Stellen finden, wo von dieser> Annahme ausgegangen wird.
Natürlich. Aber eine der Zielplattformen in diesem Thread ist AVR. Da
hilfts nichts, daß auf den Plattformen, für die C gedacht war, int
keinen Nachteil hätte. Ich empfehle auch nicht einen Porsche zum Ziehen
eines Pflugs, nur weil der auf der Straße viel schneller als ein Traktor
wäre.
>> Nun rechnet man aber mit Fehlercodes in der Regel nicht, sondern setzt>> sie nur und vergleicht sie. Dazu muß nirgends irgendein Ergebnis auf 8>> Bit beschnitten werden.>> Das weiß der Compiler aber nicht, und das steht auch nicht so im> Standard.
Natürlich weiß er, daß er nicht gerechnet hat. Oder denkst du, der
schneidet einfach vorsichtshalber regelmäßig immer wieder mal die oberen
Bits ab, nur um sicher zu sein, daß nicht eins versehentlich umgekippt
ist?
Bei einem
1
uint8_tadd(uint8_ta,uint8_tb)
2
{
3
returna+b;
4
}
muß er natürlich das Ergebnis beschneiden, aber bei
1
uint8_tmachwas(void)
2
{
3
if(fehler)
4
return3;
5
else
6
return0;
7
}
muß er das nicht tun, denn er kann sich einigermaßen sicher sein, daß
die Bits außerhalb des Bereichs von uint8_t schon alle 0 sind.
Dr. Sommer schrieb:> Und mit "g++" statt "gcc" kompilieren. Allerdings nur zu empfehlen wenn> viel RAM&Programmspeicher da ist und dynamische Speicherverwaltung.
Und wenn Exception Handling auf der Zielplattform überhaupt tut.
Dr. Sommer schrieb:> Rolf Magnus schrieb:>> Und wenn Exception Handling auf der Zielplattform überhaupt tut.> Mit ARM-GCC (siehe Topic-Titel) - JA.
Aber mit AVR-GCC, der ebenfalls im Titel steht, nicht.