Daniel's page
C Source Code Portability

Functions (limited to libc and "system" ones), general often-used concepts and variable types. Include known flaws, work-arounds, autoconf tests and general comments from past experiences.

If you find flaws or have additional data to offer, please mail me. My email address is visible at the bottom of the page. This page is destined to always be "under construction".

Related useful resources: predef.sf.net, Unix Incompatibility Notes, Tips For Writing Portable C

Functions

FunctionIssues
basenameFreeBSD 3.4 does not include the standard function basename().
bcopyOld-style BSD function, use memcpy() for portability
bzeroOld-style BSD function, use memset() for portability
gettimeofdayNot available on Windows, otherwise widely available. clock_gettime() is a newer POSIX/TSUSv2 function with higher resolution.
getaddrinfoOnly available in recent modern operating systems (gethostbyname() must be used on the others). NI_WITHSCOPEID (not present in mingw, glibc 2.3.2, Tru64 5.1, IRIX 6.5.22) and AI_NUMERICHOST (not present in AIX 4.3) are not universally available even if the getaddrinfo() function is present

Using the PF_UNSPEC option on Linux hosts that are ipv6-enabled but that doesn't have the ipv6 kernel module loaded cause very slow name resolves. This is usually worked around by first trying if a ipv6 socket can be made and if not, no ipv6 resolves are attempted (PF_INET).

gethostbyaddr_rNot needed on Windows, HP-UX 11 and AIX 5 (since gethostbyaddr() is then thread-safe on its own). Not existant on older platforms. Three different APIs:

5 arg version: int gethostbyaddr_r(char *address, int length, int type, struct hostent *he, struct hostent_data *data)

7 arg version: struct hostent *gethostbyaddr_r(char *address, int length, int type, struct hostent *he, char *buffer, int bufsize, int *errno)

8 arg version: struct hostent *gethostbyaddr_r(char *address, int length, int type, struct hostent *he, char *buffer, int bufsize, struct hostent **hep, int *errno)

gethostbyname_rNot needed on Windows, HP-UX 11 and AIX 5 (since gethostbyname() is then thread-safe on its own). Not existant on older platforms.
Three different APIs.

AIX4, Digital Unix/Tru64, HPUX 10 use 3 arguments: int gethostbyname_r(char *hostname, struct hostent *hostent, struct hostent_data *data)

Solaris (needs to be linked with -lnsl) and IRIX use 5 arguments: int gethostbyname_r(char *hostname, struct hostent *hostent, char *buffer, int buflen, int *h_errnop)

Linux uses 6 arguments: int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop)

gethostbynameFound in different libs in different operating systems. Could be one of these: -lnsl (Solaris), -lsocket, -lws2_32 (Windows), and -lnet (BeOS). See also gethostbyname_r
localtime_rNot present in all unixes. Broken implementation in HPUX 10.20 (it returns an 'int' instead of a pointer - is that 0 for success?)
strerror_rNot present everywhere (like Windows, Solaris 7). But when it is, there's a POSIX way (int strerror_r(int errnum, char *buf, size_t n)) and there's a glibc way (char *strerror_r(int errnum, char *buf, size_t n))
inet_ntoa_rNot present in all unixes.
strtok_rNot present in all unixes. Standardized in UNIX98 (aka SUSv2)
getpass_rNot present in all unixes. In fact, this is rarely available. (SCO Unix has it)
gmtime_rBroken implementation in HPUX 10.20 (it returns an 'int' instead of a pointer - is that 0 for success?)
selectWindows quirks: you can only select on sockets. You cannot know if a FD_SET() would overflow the buffer since the file descriptor numbering starts way above 0 and comparisons against FD_SETSIZE are not working. FD_SETSIZE is typically set very low (64) by default.

Many unix versions allow FD_SETSIZE to be re-defined at compile time, but Linux does not.

Linux has odd semantics, the following is from the BUGS section of select(2)

Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.

pollNot existing on old unixes. Broken implementation in Mac OS X at least up to 10.4 and earlier. Up to 10.3 you could check for a poll() that works with all arguments zeroed. The 10.4 bug is more obscure an I don't know of any way to detect it without checking for OS.
snprintfEssential function that is lacking in older unixes (SunOS) and Windows. Different implementations return differen values in case of prevented overflow. autoconf macro for C99-compliant snprintf trio *printf code
sprintfReturns either a 'char *' as a pointer to the output buffer (SunOS, 4.3 BSD) or an int as the length of the output data (most others, POSIX).
strcasecmpSome platforms (Reliant and UnixWare) have this in the resolve lib, requiring -lresolve to link fine.
socket Needs -lnsl -lsocket in LDFLAGS to link on Solaris

On Win64 it returns a SOCKET which is 64 bits, while (all?) other systems return an int, 32 bits.

sigactionHPUX doesn't have SA_RESTART, but instead it defaults to the same behaviour as other systems that do have gets when ANDing out the SA_RESTART bit from sigact.sa_flags

Concepts

ConceptDescription
Non-blocking socketsDone in lots of different ways:

The POSIX approach (known to not work on SunOS 4, AIX v3 and BeOS - although the function and defines are present) fcntl(socket, F_SETFL, flags | O_NONBLOCK)

BSD-style ioctl(socket, FIONBIO, &flags)

Windows-style ioctlsocket(socket, FIONBIO, &flags)

AmigaOS-style IoctlSocket(socket, FIONBIO, (long)1)

BeOS-style setsockopt(socket, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))

Avoiding SIGPIPEDone in several ways:

Ignore signal (using sigaction() or signal(), the latter more widely available)

Mac OS X 10.2 and later (at least): setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, sizeof(onoff))

Most other systems support send/recv(x,y,z, MSG_NOSIGNAL)

Building thread-safe-D_THREAD_SAFE -D_REENTRANT (Solaris, HPUX) and more? [FILL IN]
libcWindows quirks: the libc is provided by the compiler, not by the operating system. Thus, various libc function calls may differ between compilers.
case insensitive string comparisons Most systems: int strcasecmp()
Windows: int strcmpi() or int stricmp()
writeable argv[] Many systems allow programs to overwrite the argv[] strings to hide data from appearing in ps outputs (Linux, Solaris 7, HP-UX 11, Tru64 V5, IRIX 6.5)
inline Was not a standard keyword until C99. Before that, compilers provided various own approaches (gcc supports inline since very long).

Variable Types

TypeIssues
time_tOften a signed 32bit type, sometimes unsigned 32bit (OpenVMS), and sometimes still 32bit even when running in a 64bit arch (AIX) and even sometimes 64bit on 32bit systems (VS2005)
size_tPOSIX type not always present on old systems. strlen() and family returns size_t in POSIX
ssize_tCommonly used signed version of size_t. Not present on numerous systems.
in_addr_tNot present on many pre-POSIX systems. Functions that otherwise use in_addr_t usually use int on those.
socklen_tNot present on many pre-POSIX systems. Functions that otherwise use socklen_t usually use int on those.

AIX 4.2 curiously uses an unsigned type for this. (AIX -4.1 was int, AIX 4.3+ is socklen_t)

struct sockaddr_storageNot present in AIX 4.3 even though it has getaddrinfo() and other IPv6-ready functions
off_tPOSIX type for file sizes. Not present on older systems. Usually 32 or 64 bit.

Contributions by
Bjorn Reese, Magnus Fromreide

Thanks!

Latest update: July 30, 2010

daniel at haxx dot .se