Ik heb een functie die ik op éénvan de vier mogelijke manieren kan schrijven:
int do_or_die(int retval);
int do_or_die(ssize_t retval);
ssize_t do_or_die(int retval);
ssize_t do_or_die(ssize_t retval);
En dan wordt het aangeroepen met beidevan deze manieren voor bibliotheekfuncties:
written = do_or_die(write(...)); // POSIX write returns ssize_t
printed = do_or_die(printf(...)); // printf returns int
Vragen
- Welk prototype moet ik gebruiken?
- Welke soorten moet ik geven aan
written
enprinted
?
Ik wil de meest robuuste en standaardcode hebben, terwijl ik nog steeds maar één do_or_die
-functie heb.
In dit geval gebruik ik C99, maar als het antwoord voor C11 anders is, dan zou ik dat ook graag willen weten voor de toekomst.
Antwoord 1, autoriteit 100%
Er is geen garantie in de POSIX-standaard dat sizeof(int) >= sizeof(ssize_t)
, noch andersom. Meestal is ssize_t
groter dan int
, maar de veilige en draagbare optie in C99 is om in plaats daarvan intmax_t
te gebruiken voor het argument en de retourwaarde.
De enige garanties die je hebt tov. de relatie tussen int
en ssize_t
zijn:
int
kan waarden opslaan van ten minste het bereik [-2^15 … 2^15-1] per ISO Cssize_t
kan waarden van ten minste het bereik [-1 … 2^15-1] per POSIX opslaan (zie_POSIX_SSIZE_MAX
).
(Interessant is dat er zelfs geen garantie is dat ssize_t
de negatieve tegenhangers van zijn positieve bereik kan opslaan. Het is geen ondertekende size_t
, maar een “maattype ” met een foutwaarde.)
Antwoord 2, autoriteit 9%
Gebruik typen op een bepaalde manier:
- je mengt
signed
enunsigned
typen niet door elkaar en - u kapt geen waarden af van grotere typen terwijl u ze opslaat in kleinere typen (overloop/onderloop)
ssize_t
is misschien een alias voor int
, maar het is geen standaard C en kan omgevingsspecifiek zijn.
Als uw programma in een specifieke omgeving draait, controleer dan of sizeof(ssize_t) <= sizeof(int)
en gebruik int
. Gebruik anders een ander type T
waarbij sizeof(T)
groter of gelijk is aan zowel sizeof(int)
als sizeof(ssize_t)
.
Antwoord 3
U kunt de gegevenstypen int of long int gebruiken, maar ssize_t
is een systeemgegevenstype dat moet worden gebruikt voor platformonafhankelijke portabiliteit. De fundamentele typen (zoals ‘int’) kunnen verschillende groottes hebben bij verschillende implementaties. Wat er meestal gebeurt, is dat het systeemtype (in dit geval ssize_t
) gebruikmaakt van de typedef-functie van C, zodat de machinespecifieke grootte van het gegevenstype wordt gebruikt, b.v. typedef signed ssize_t
(dit maakt deel uit van SUSv3 standaard datatypes). Het is een goede gewoonte om, waar mogelijk, systeemgegevenstypen te gebruiken bij het implementeren van enige vorm van programmering op systeemniveau.
Raadpleeg voor een meer gedetailleerde beschrijving de Linux-programmeerinterface (Michael Kerrisk)