Code
I've got a function which I can write in one of four possible ways:
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); And then it will be called with both of these ways for library functions:
written = do_or_die(write(...)); // POSIX write returns ssize_t printed = do_or_die(printf(...)); // printf returns intQuestions
- Which prototype should I use?
- What types should I give to
writtenandprinted?
I want to have the most robust and standard code, while still having just one do_or_die function.
I am using C99 in this case, but if answer is different for C11, then I'd like to know that too, for future.
53 Answers
There's no guarantee in the POSIX standard that sizeof(int) >= sizeof(ssize_t), nor the other way around. Typically ssize_t is larger than int, but the safe and portable option in C99 is to use intmax_t instead for the argument and the return value.
The only guarantees you have wrt. the relationship between int and ssize_t are:
intcan store values of at least the range [-2^15 ... 2^15-1] per ISO Cssize_tcan store values of at least the range [-1 ... 2^15-1] per POSIX (see_POSIX_SSIZE_MAX).
(Interestingly, there isn't even a guarantee that ssize_t can store the negative counterparts of its positive range. It's not a signed size_t, but a "size type" with an error value.)
Use types in a way:
- you don't mix
signedandunsignedtypes together and - you don't truncate values from larger types while storing them in smaller types (overflow/underflow)
ssize_t might be an alias for int, yet it is not standard C and might be environment specific.
If your program will run in specific environment, check whether sizeof(ssize_t) <= sizeof(int) and use int. Otherwise, use some other type T where sizeof(T) is greater or equal than both sizeof(int) and sizeof(ssize_t).
You can use int or long int data types, however ssize_t is a system data type that should be used for cross-platform portability. The fundamental types (such as 'int') can be different sizes on different implementations. Usually what happens is the system type (in this case ssize_t) takes advantage of C's typedef feature so that the machine-specific data type size is used, e.g. typedef signed ssize_t (this is part of SUSv3 standard data types). It is good practice to use system data types, where possible, when implementing any kind of system-level programming.
For a more detailed description refer to The Linux Programming Interface (Michael Kerrisk)