2012-07-10 5 views
9

Im Normalfall open() geben Sie den neuen Dateideskriptor zurück, oder -1, wenn ein Fehler aufgetreten ist, und in diesem Fall wird errno entsprechend festgelegt.warum fopen() oder open() benutzen errno statt nur fehlercode zurückgeben?

Ich verstehe nicht, warum dieser Mechanismus von errno hier verwendet wird? Was ist der Zweck von hier? Warum können wir nicht alle Fehler mit einigen negativen Returns abbilden?

wie

fd = open("/dev/tty0", O_RDWR | O_SYNC); 
if(fd == -1) 
    printf("this is EACCES error"); 
else if (fd == -2) 
    printf("this is EPERM error"); 

Gibt es eine benifit von errno Mechanismus.? Wenn ja, dann würde ich gerne wissen/verstehen dann in anderen Dingen kann ich diesen Mechanismus auch verwenden.

Antwort

11

Seit fopen kehrt ein FILE* Sie kann nicht erwarten, dass es einen Fehlercode in diesem Zeiger zurückgibt: der einzige "spezielle" Wert für Zeiger ist 0.

Wie Sie beobachten, gilt für open diese Einschränkung nicht. In der Tat tun Systeme wie Linux genau das, was Sie in ihren unteren Ebenen vorschlagen. Der Systemaufruf unter der Haube gibt den negativen Fehlercode zurück, wenn etwas schief geht. Dieser (negierte) Code wird dann in errno von einem flachen Benutzer-Space-Wrapper gesteckt, der dann die -1 zurückgibt, um den Fehler der Anwendung anzuzeigen.

Der Grund dafür ist rein historischer Natur.In guten alten Zeiten gab es kein Threading und errno war immer noch nur eine einfache globale Variable. Zu dieser Zeit verursachte die gewählte Strategie nicht viel Overhead und schien eine akzeptable Art der Kommunikation zwischen Betriebssystem und Anwendung zu sein. Da solche Schnittstellen grundsätzlich nicht geändert werden können, ohne viel Code zu zerstören, bleiben wir bei errno als eine Pseudo-Variable, die lokal Thread ist.

Dies ist nicht ideal, aber der Overhead ist nicht so schlecht, wie es sich anhört, da diese Fehler Hinweise sind, die nur ausnahmsweise auftreten sollten.

+0

+1 sehr nette Antwort –

1

errno ist ein Fehlercode. Es ist wichtig, die Fehler den tatsächlichen Ereignissen zuzuordnen, damit Sie in Ihrem Code strategische Entscheidungen darüber treffen können, was als nächstes zu tun ist. Zum Beispiel, ERANGE, die in errno.h definiert ist, wird Ihnen sagen, dass das Ergebnis von strtol("0xfffffffff",NULL,0) außerhalb des Bereichs dieser Funktion ist. Noch wichtiger in Ihrem Beispiel, es ist gut zu wissen, ob Sie einen EACCES oder EPERM Fehler haben, damit Sie wissen, wie man mit der Datei umgeht.

Sie können nicht alle Probleme mit einem Fehlercode abbilden, da Sie mehrere Probleme haben könnten, die Sie abfangen und behandeln möchten. Wenn ich Fangen sage, meine ich nicht versuchen/fangen.

Die Verwendung von Fehlernummern und Fehlerbehandlung Mechanismus, so erhalten Sie mehr Informationen als nur -1.

ERANGE, EACCES, EPERM und andere werden als Makros betrachtet, die aus praktischen Gründen einer bestimmten Fehlernummer zugeordnet werden.

9

Für mich ist der Vorteil ist, dass die Fehlerinformationen bekommen auf diese Weise vereinigt ist, funktionieren würde, einige negativen Wert zurück OK mit open, da es eine ganze Zahl zurückgibt, aber fopen gibt eine FILE * so wäre eine andere Technik verwendet, dort werden müssen.

+0

FILE * ist immer noch Zeiger auf einen Puffer/Speicher, so dass es nie negativ sein wird. Wenn also ein Fehler auftritt, geben wir FILE * nicht mit negativem Wert zurück? weil NULL ist 0 –

+6

Ein Zeiger hat - zumindest auf den Architekturen, die ich kenne - kein Konzept der Signedness, es kann (theoretisch) den gesamten Bereich der "zugrunde liegenden vorzeichenlosen Integer" (dh ein 32bit Punkt kann von 0x00000000 bis 0xffffffff gehen) . Und 'NULL' ist nur und ein Hinweis, um zu sagen" hey, das ist fehlgeschlagen, sieh zu errno, um zu sehen, was schief gelaufen ist " – fvu

+0

Theoretisch könnte eine Reihe von reservierten Zeigern auch verwendet werden; alles was benötigt wird ist 'char err_ptrs [MAX_ERRNO]; void * EACCESS_ptr = err_ptrs + EACCESS; 'usw. um' EACCESS_ptr' zu einem gültigen "Fehlercode" für Zeiger zu machen. Wenn Sie sie jedoch als Integer und Zeiger duplizieren müssen und die Tatsache, dass einige Schnittstellen den gesamten Abstand von Integer-Werten als gültige Rückgabewerte verwenden, macht errno trotzdem Sinn. –

1

Wenn man jeder Funktion einen eigenen Satz von Rückgabewerten gibt, ist es zu kompliziert, Code in generischer Form zu schreiben. Mit den aktuellen Semantik, können Sie ein universelles Muster annehmen:

int fd; 
if ((fd = some_function(arg1, arg2)) == -1) 
{ 
    perror("some_function"); 
    exit(1); 
} 

Sie können sogar diese wickeln in einem Makro:

#define CALL_OR_DIE(function, ret, ...)  \ 
    if ((ret = function(__VA_ARGS__)) == -1) \ 
    { perror(#function); exit(1); } 

Verbrauch:

int fd; 
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC); 
+1

Sie sagen also (1), dass es besser ist, '== -1' zu schreiben als' <0' (mit Fehlern, die als negativ definiert sind), und (2) das ist die Motivation für 'errno'? Ich nehme an, es hat einen Vorteil, im Fehlerfall 'fd' nicht auf' perror' zu übertragen, weil es aus dem thread-lokalen 'errno' gelesen werden kann, aber ich denke nicht, dass es vollständig erklärt, warum das errno isn ist Ich bin auch nicht von "offen" zurückgekommen. –

Verwandte Themen