[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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
returnedint
. This is becauseexit
predatesvoid
, and there was a long tradition of it returningint
.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 invokeexit
, but return frommain
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
andisnan
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
andisnan
macros work correctly withlong double
arguments, but pre-C99 systems that use functions typically assumedouble
arguments. On such a system,isinf
incorrectly returns true for a finitelong double
argument that is outside the range ofdouble
.The best workaround for these issues is to use gnulib modules
isinf
andisnan
(see section Gnulib). But a lighter weight solution involves 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) && isnan (x - x); } static inline int isinf_d (double x) { return !isnan (x) && isnan (x - x); } static inline int isinf_ld (long double x) { return !isnan (x) && isnan (x - x); } #endif
Use
AC_C_INLINE
(see section C Compiler Characteristics) so that this code works on compilers that lack theinline
keyword. 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 call
malloc (0)
is implementation dependent. It can return eitherNULL
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
(see section Particular Function Checks). -
putenv
-
Posix prefers
setenv
toputenv
; among other things,putenv
is not required of all Posix implementations, butsetenv
is.Posix specifies that
putenv
puts the given string directly inenviron
, 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 tomalloc (size)
, but some old systems don't support this (e.g., NextStep). -
signal
handler -
Normally
signal
takes a handler function with a return type ofvoid
, but some old systems requiredint
instead. Any actualint
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
. Theint
was to support K&R C, where of coursevoid
is not available. The obsolete macroAC_TYPE_SIGNAL
(see AC_TYPE_SIGNAL) can be used to establish the correct type in all cases.In most cases, it is more robust to use
sigaction
when it is available, rather thansignal
. -
snprintf
-
The C99 standard says that if the output array isn't big enough and if no other errors occur,
snprintf
andvsnprintf
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
andvsprintf
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 usinggcc
since it normally puts constant strings in read-only memory (see Incompatibilities of GCC: (gcc)Incompatibilities section `Incompatibilities' in Using and Porting the GNU Compiler Collection). Apparently in some cases even having format strings read-only can be a problem. -
strerror_r
-
Posix specifies that
strerror_r
returns anint
, but many systems (e.g., GNU C Library version 2.2.4) provide a different version returning achar *
.AC_FUNC_STRERROR_R
can detect which is in use (see section Particular Function Checks). -
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 callputenv ("FOO=")
, as described underputenv
above. -
va_copy
-
The C99 standard provides
va_copy
for copyingva_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 tomemcpy (&dst, &src, sizeof (va_list))
gives maximum portability. -
va_list
-
va_list
is not necessarily just a pointer. It can be astruct
(e.g.,gcc
on Alpha), which meansNULL
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |