File: autoconf.info, Node: Function Portability, Next: Particular Functions, 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 always requires additions.
A much more complete list is maintained by the Gnulib project (*note
Gnulib::), covering *note Current Posix Functions: (gnulib)Function
Substitutes, *note Legacy Functions: (gnulib)Legacy Function
Substitutes, and *note Glibc Functions: (gnulib)Glibc Function
Substitutes. Please help us keep the Gnulib list as complete as
possible.
‘exit’
On ancient hosts, ‘exit’ returned ‘int’. This is because ‘exit’
predates ‘void’, and there was a long tradition of it returning
‘int’.
On current hosts, the problem more likely is that ‘exit’ is not
declared, due to C++ problems of some sort or another. For this
reason we suggest that test programs not invoke ‘exit’, but return
from ‘main’ instead.
‘isinf’
‘isnan’
In C99 and later, ‘isinf’ and ‘isnan’ are macros. On some systems
just macros are available (e.g., HP-UX and Solaris 10), on some
systems both macros and functions (e.g., glibc 2.3.2), and on some
systems only functions (e.g., IRIX 6). In some cases these
functions are declared in nonstandard headers like ‘’
and defined in non-default libraries like ‘-lm’ or ‘-lsunmath’.
In C99 and later, ‘isinf’ and ‘isnan’ macros work correctly with
‘long double’ arguments, but pre-C99 systems that use functions
typically assume ‘double’ arguments. On such a system, ‘isinf’
incorrectly returns true for a finite ‘long double’ argument that
is outside the range of ‘double’.
The best workaround for these issues is to use Gnulib modules
‘isinf’ and ‘isnan’ (*note Gnulib::). But a lighter weight
solution involves code like the following.
#include
#ifndef isnan
# define isnan(x) \
(sizeof (x) == sizeof (long double) ? isnan_ld (x) \
: sizeof (x) == sizeof (double) ? isnan_d (x) \
: isnan_f (x))
static int isnan_f (float x) { return x != x; }
static int isnan_d (double x) { return x != x; }
static int isnan_ld (long double x) { return x != x; }
#endif
#ifndef isinf
# define isinf(x) \
(sizeof (x) == sizeof (long double) ? isinf_ld (x) \
: sizeof (x) == sizeof (double) ? isinf_d (x) \
: isinf_f (x))
static int isinf_f (float x)
{ return !isnan (x) && isnan (x - x); }
static int isinf_d (double x)
{ return !isnan (x) && isnan (x - x); }
static int isinf_ld (long double x)
{ return !isnan (x) && isnan (x - x); }
#endif
Some optimizing compilers mishandle these definitions, but systems
with that bug typically have many other floating point corner-case
compliance problems anyway, so it's probably not worth worrying
about.
‘malloc’
The C standard says a successful call ‘malloc (0)’ is
implementation dependent. It can return either ‘NULL’ or a new
non-null pointer. The latter is more common (e.g., the GNU C
Library) but is by no means universal. ‘AC_FUNC_MALLOC’ can be
used to insist on non-‘NULL’ (*note Particular Functions::).
‘putenv’
Posix prefers ‘setenv’ to ‘putenv’; among other things, ‘putenv’ is
not required of all Posix implementations, but ‘setenv’ is.
Posix specifies that ‘putenv’ puts the given string directly in
‘environ’, but some systems make a copy of it instead (e.g., glibc
2.0, or BSD). And when a copy is made, ‘unsetenv’ might not free
it, causing a memory leak (e.g., FreeBSD 4).
On some systems ‘putenv ("FOO")’ removes ‘FOO’ from the
environment, but this is not standard usage and it dumps core on
some systems (e.g., AIX).
On MinGW, a call ‘putenv ("FOO=")’ removes ‘FOO’ from the
environment, rather than inserting it with an empty value.
‘realloc’
It is problematic to call ‘realloc’ with a zero size. The C
standard says ‘realloc (NULL, 0)’ is equivalent to ‘malloc (0)’,
which means one cannot portably tell whether the call has succeeded
if it returns a null pointer. If ‘ptr’ is non-null, the C standard
says ‘realloc (ptr, 0)’ has undefined behavior.
The ‘AC_FUNC_REALLOC’ macro avoids some of these portability
issues, and the Gnulib module ‘realloc-gnu’ avoids more of them.
*Note Particular Functions::.
‘signal’ handler
In most cases, it is more robust to use ‘sigaction’ when it is
available, rather than ‘signal’.
‘snprintf’
In C99 and later, 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 ancient systems returned the truncated length (e.g., GNU C
Library 2.0.x or IRIX 6.5), and some a negative value (e.g.,
earlier GNU C Library versions).
‘strerror_r’
Posix specifies that ‘strerror_r’ returns an ‘int’, but many
systems (e.g., GNU C Library version 2.36) provide a different
version returning a ‘char *’. ‘AC_FUNC_STRERROR_R’ can detect
which is in use (*note Particular Functions::).
‘strnlen’
AIX 4.3 provided 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 (e.g., 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.
Some non-Posix hosts have trouble with this requirement, though,
and some DOS variants even corrupt the file system.
‘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’
C99 and later provide ‘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 pre-C99 mode). These can be
tested with ‘#ifdef’. A fallback to ‘memcpy (&dst, &src, sizeof
(va_list))’ gives 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 Standard C doesn't require that behavior. On a few
platforms (e.g., Cray C by default) zero bits are shifted in, the
same as a shift of an unsigned type.
Integer ‘/’
C divides signed integers by truncating their quotient toward zero,
yielding the same result as Fortran. However, before C99 the
standard allowed C implementations to take the floor or ceiling of
the quotient in some cases. Hardly any implementations took
advantage of this freedom, though, and it's probably not worth
worrying about this issue nowadays.