Next: , Up: Library Functions


5.5.1 Portability of C Functions

Most usual functions can either be missing, or be buggy, or be limited on some architectures. This section tries to make an inventory of these portability issues. By definition, this list will always require additions. Please help us keeping it as complete as possible.

exit
Did you know that, on some older hosts, exit returns int? This is because exit predates void, and there was a long tradition of it returning int.
putenv
POSIX specifies that putenv puts the given string directly in environ, but some systems make a copy of it instead (eg. glibc 2.0, or BSD). And when a copy is made, unsetenv might not free it, causing a memory leak (eg. FreeBSD 4).

POSIX specifies that putenv("FOO") removes `FOO' from the environment, but on some systems (eg. FreeBSD 4) this is not the case and instead unsetenv must be used.

On MINGW, a call putenv("FOO=") removes `FOO' from the environment, rather than inserting it with an empty value.

signal handler
Normally signal takes a handler function with a return type of void, but some old systems required int instead. Any actual int value returned is not used, this is only a difference in the function prototype demanded.

All systems we know of in current use take void. Presumably int was to support K&R C, where of course void is not available. AC_TYPE_SIGNAL (see Particular Types) can be used to establish the correct type in all cases.

snprintf
The ISO C99 standard says that if the output array isn't big enough and if no other errors occur, snprintf and vsnprintf truncate the output and return the number of bytes that ought to have been produced. Some older systems return the truncated length (e.g., GNU C Library 2.0.x or irix 6.5), some a negative value (e.g., earlier GNU C Library versions), and some the buffer length without truncation (e.g., 32-bit Solaris 7). Also, some buggy older systems ignore the length and overrun the buffer (e.g., 64-bit Solaris 7).
sprintf
The ISO C standard says sprintf and vsprintf return the number of bytes written, but on some old systems (SunOS 4 for instance) they return the buffer pointer instead.
sscanf
On various old systems, e.g., HP-UX 9, sscanf requires that its input string be writable (though it doesn't actually change it). This can be a problem when using gcc since it normally puts constant strings in read-only memory (see Incompatibilities of GCC). Apparently in some cases even having format strings read-only can be a problem.
strnlen
AIX 4.3 provides a broken version which produces the following results:
          strnlen ("foobar", 0) = 0
          strnlen ("foobar", 1) = 3
          strnlen ("foobar", 2) = 2
          strnlen ("foobar", 3) = 1
          strnlen ("foobar", 4) = 0
          strnlen ("foobar", 5) = 6
          strnlen ("foobar", 6) = 6
          strnlen ("foobar", 7) = 6
          strnlen ("foobar", 8) = 6
          strnlen ("foobar", 9) = 6
     

sysconf
_SC_PAGESIZE is standard, but some older systems (eg. HP-UX 9) have _SC_PAGE_SIZE instead. This can be tested with #ifdef.
unlink
The POSIX spec says that unlink causes the given file to be removed only after there are no more open file handles for it. Not all OS's support this behavior though. So even on systems that provide unlink, you cannot portably assume it is OK to call it on files that are open. For example, on Windows 9x and ME, such a call would fail; on DOS it could even lead to file system corruption, as the file might end up being written to after the OS has removed it.
unsetenv
On MINGW, unsetenv is not available, but a variable `FOO' can be removed with a call putenv("FOO="), as described under putenv above.
va_copy
The ISO C99 standard provides va_copy for copying va_list variables. It may be available in older environments too, though possibly as __va_copy (e.g., gcc in strict C89 mode). These can be tested with #ifdef. A fallback to memcpy (&dst, &src, sizeof(va_list)) will give maximum portability.
va_list
va_list is not necessarily just a pointer. It can be a struct (e.g., gcc on Alpha), which means NULL is not portable. Or it can be an array (e.g., gcc in some PowerPC configurations), which means as a function parameter it can be effectively call-by-reference and library routines might modify the value back in the caller (e.g., vsnprintf in the GNU C Library 2.1).
Signed >>
Normally the C >> right shift of a signed type replicates the high bit, giving a so-called “arithmetic” shift. But care should be taken since the ISO C standard doesn't require that behavior. On those few processors without a native arithmetic shift (for instance Cray vector systems) zero bits may be shifted in, the same as a shift of an unsigned type.