Helmut Waitzmann
2019-04-05 15:44:13 UTC
while ((rc = read(fd, buf, len)), rc == -1 && errno == EAGAIN) {
[...] ich formuliere stets'rc < 0', weil jeder Wert <0 eine Fehlersituation ist.
read(). Von daher ist das wurscht.
außer ihn als Fehler anzusehen, nichts anfangen kann.
relevant, auf einem 32-Bit-System 3 Gigabyte am Stück zu lesen, aber auf
einem 16-Bitter 40 kByte find ich jetzt nicht ungewöhnlich. Dann wäre
der Erfolgswert -24576.
Nicht, dass sich MS-DOS darum scheren würde, aber POSIX (SUS) lässt
diesen Fall implementation-defined.
|Return values
|On success, read and readv return a non-negative integer
|indicating the number of bytes actually read.
|On failure, read and readv return -1
|and set errno to identify the error.
'Success' erfordert unbedingt Werte >= 0.
IEEE Std 1003.1™-2017 (Revision of IEEE Std 1003.1-2008):
<http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html#tag_16_474_02>:
SYNOPSIS
#include <unistd.h>
[…]
ssize_t read(int fildes, void *buf, size_t nbyte);
<http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html#tag_16_474_03>:
DESCRIPTION
The read() function shall attempt to read nbyte bytes from
the file associated with the open file descriptor, fildes,
into the buffer pointed to by buf.
[…]
If the value of nbyte is greater than {SSIZE_MAX}, the
result is implementation-defined.
<http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html#tag_16_474_04>:
RETURN VALUE
Upon successful completion, these functions shall return a
non-negative integer indicating the number of bytes actually
read. Otherwise, the functions shall return -1 and set errno
to indicate the error.
=> Über Funktionswerte <-1 wird im POSIX‐Standard keine Aussage
gemacht, außer der, dass für den Fall, dass mehr als SSIZE_MAX
Bytes gelesen werden sollen, die Implementierung festlegen muss,
was dann geschehen soll. Der C‐Standard macht überhaupt keine
Aussage, weil die Funktion »read()« nicht darin enthalten ist.
Das war auch schon so, als beide Typen 'int' waren.
Daß die Typen heute ssize_t und size_t sind, ändert nichts daran.
Wenn heute ein Wert 'len' übergeben wird, der größer ist als
der positive Wertbereich von ssize_t, werden eben weniger Bytes
in 'buf' kopiert als per 'len' angegeben, oder es wird
der Fehler EOVERFLOW oder ein anderer gegeben.
Mit ersterem muß sowieso gerechnet werden.
Das geben weder der POSIX‐ noch der C‐Standard her.Daß die Typen heute ssize_t und size_t sind, ändert nichts daran.
Wenn heute ein Wert 'len' übergeben wird, der größer ist als
der positive Wertbereich von ssize_t, werden eben weniger Bytes
in 'buf' kopiert als per 'len' angegeben, oder es wird
der Fehler EOVERFLOW oder ein anderer gegeben.
Mit ersterem muß sowieso gerechnet werden.
Fazit: Wer will, dass sein Programm auf jedem POSIX‐System
funktioniert, muss sich darauf beschränken, nicht mehr als
SSIZE_MAX Bytes lesen zu wollen. Hält er sich an die
Beschränkung, können Funktionswerte <-1 (bisher) nicht vorkommen.
Tut er es nicht, erklärt er sich mit dem einverstanden, was seine
Implementierung festgelegt hat.
Will man also wasserdicht programmieren, sind Funktionswerte >=0
als Anzahl gelesener Bytes, der Funktionswert =-1 als im Standard
definierter Fehlerfall mit im Standard definierten
Fehlerbehandlungsmöglichkeiten und Funktionswerte < -1 als
verbotene Werte zu behandeln. »Verboten« heißt: Das Programm
kann überhaupt keine Annahmen mehr über den Zustand des
File‐Descriptors machen. Es bleibt ihm nicht viel anderes übrig,
als (nach Belieben) dem Anwender eine Fehlermeldung über einen den
Standard sprengenden Fehler zu geben und danach diesen
File‐Descriptor nicht mehr anzufassen (allenfalls noch, ihn zu
schließen).
Siehe auch
<http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html#tag_16_474_08_01>.
Wenn ich das richtig verstanden habe, ist die Funktion »read()« im
C‐Standard nicht definiert, jedoch im POSIX‐Standard. Deshalb
schlage ich ein
Crosspost & Followup-To: de.comp.os.unix.programming
vor. Notfalls bitte passend abändern.