|
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. Please help us keeping it 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.
free -
The C standard says a call
free (NULL) does nothing, but
some old systems don't support this (e.g., NextStep).
isinf isnan -
The C99 standard says that
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 and Solaris 9). In some cases
these functions are declared in nonstandard headers like
<sunmath.h> and defined in non-default libraries like
-lm or -lsunmath.
The C99 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 .
To work around this porting mess, you can use code like the following.
#include <math.h>
#ifndef isnan
# define isnan(x) \
(sizeof (x) == sizeof (long double) ? isnan_ld (x) \
: sizeof (x) == sizeof (double) ? isnan_d (x) \
: isnan_f (x))
static inline int isnan_f (float x) { return x != x; }
static inline int isnan_d (double x) { return x != x; }
static inline 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 inline int isinf_f (float x) { return isnan (x - x); }
static inline int isinf_d (double x) { return isnan (x - x); }
static inline int isinf_ld (long double x) { return isnan (x - x); }
#endif
Use AC_C_INLINE (see C Compiler) so that this code works on
compilers that lack the inline keyword. Some optimizing
compilers mishandle these definitions, but systems with that bug
typically have missing or broken isnan functions anyway, so it's
probably not worth worrying about.
malloc -
The C standard says a call
malloc (0) is implementation
dependent. It may either return NULL (e.g., OSF 4) or
non-NULL (e.g., GNU C Library). AC_FUNC_MALLOC
can be used to insist on non-NULL (see 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 -
The C standard says a call
realloc (NULL, size) is equivalent
to malloc (size) , but some old systems don't support this (e.g.,
NextStep).
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 return void . The
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 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 C standard says
sprintf and vsprintf return the
number of bytes written. On some ancient systems (SunOS 4 for
instance) they return the buffer pointer instead, but these no
longer need to be worried about.
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.
strerror_r -
Posix specifies that
strerror_r returns an int , but many
systems (e.g., GNU C Library version 2.2.4) provide a
different version returning a char * . AC_FUNC_STRERROR_R
can detect which is in use (see Particular Functions).
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 (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 -
The 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
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 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.
- 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.
|
|