C Source Code Portability
Functions (limited to libc and "system" ones), general often-used concepts andvariable types. Include known flaws, work-arounds, autoconf tests and generalcomments from past experiences.
If you find flaws or have additional data to offer, please mail me. My emailaddress is visible at the bottom of the page. This page is destined to alwaysbe "under construction".
Related useful resources: predef.sf.net, Unix IncompatibilityNotes, Tips ForWriting Portable C
Function | Issues |
---|---|
basename | FreeBSD 3.4 does not include the standard function basename(). |
bcopy | Old-style BSD function, use memcpy() for portability |
bzero | Old-style BSD function, use memset() for portability |
gettimeofday | Not available on Windows, otherwise widely available. clock_gettime() is a newer POSIX/TSUSv2 function with higher resolution. |
getaddrinfo | Only available in recent modern operating systems(gethostbyname() must be used on the others). NI_WITHSCOPEID (not present inmingw, glibc 2.3.2, Tru64 5.1, IRIX 6.5.22) and AI_NUMERICHOST (not present inAIX 4.3) are not universally available even if the getaddrinfo() function ispresent Using the PF_UNSPEC option on Linux hosts that are ipv6-enabledbut that doesn't have the ipv6 kernel module loaded cause very slow nameresolves. This is usually worked around by first trying if a ipv6 socket canbe made and if not, no ipv6 resolves are attempted (PF_INET). |
gethostbyaddr_r | Not needed on Windows, HP-UX 11 and AIX 5(since gethostbyaddr() is then thread-safe on its own). Not existant on olderplatforms. Three different APIs: 5 arg version: int gethostbyaddr_r(char *address, intlength, 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_r | Not needed on Windows, HP-UX 11 and AIX 5(since gethostbyname() is then thread-safe on its own). Not existant on olderplatforms. Three different APIs. AIX4, Digital Unix/Tru64, HPUX 10 use 3 arguments: intgethostbyname_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) |
gethostbyname | Found in different libs in different operatingsystems. Could be one of these: -lnsl (Solaris), -lsocket, -lws2_32 (Windows),and -lnet (BeOS). See also gethostbyname_r |
localtime_r | Not present in all unixes. Broken implementationin HPUX 10.20 (it returns an 'int' instead of a pointer - is that 0 forsuccess?) |
strerror_r | Not present everywhere (like Windows, Solaris7). But when it is, there's a POSIX way (intstrerror_r(int errnum, char *buf, size_t n)) and there's a glibc way(char *strerror_r(int errnum, char *buf, size_tn)) |
inet_ntoa_r | Not present in all unixes. |
strtok_r | Not present in all unixes. Standardized in UNIX98(aka SUSv2) |
getpass_r | Not present in all unixes. In fact, this is rarelyavailable. (SCO Unix has it) |
gmtime_r | Broken implementation in HPUX 10.20 (it returns an'int' instead of a pointer - is that 0 for success?) |
select | Windows quirks: you can only select on sockets. Youcannot know if a FD_SET() would overflow the buffer since the file descriptornumbering starts way above 0 and comparisons against FD_SETSIZE are notworking. FD_SETSIZE is typically set very low (64) by default. Many unix versions allow FD_SETSIZE to be re-defined at compile time, butLinux 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. |
poll | Not existing on old unixes. Broken implementation in MacOS 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'tknow of any way to detect it without checking for OS. |
snprintf | Essential function that is lacking in older unixes(SunOS) and Windows. Different implementations return differen values in caseof prevented overflow. autoconf macrofor C99-compliant snprintf trio *printfcode |
sprintf | Returns either a 'char *' as a pointer to the outputbuffer (SunOS, 4.3 BSD) or an int as the length of the output data (mostothers, POSIX). |
strcasecmp | Some platforms (Reliant and UnixWare) have this inthe resolve lib, requiring -lresolve to link fine. |
socket | Needs -lnsl -lsocket in LDFLAGS to link onSolaris On Win64 it returns a SOCKET which is 64 bits, while (all?) other systemsreturn an int, 32 bits. |
sigaction | HPUX doesn't have SA_RESTART, but instead itdefaults to the same behaviour as other systems that do have gets when ANDingout the SA_RESTART bit from sigact.sa_flags |
Concept | Description |
---|---|
Non-blocking sockets | Done in lots of different ways: The POSIX approach (known to not work on SunOS 4, AIX v3 and BeOS - althoughthe 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 SIGPIPE | Done in several ways: Ignore signal (usingsigaction() 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] |
libc | Windows quirks: the libc is provided by the compiler, notby the operating system. Thus, various libc function calls may differ betweencompilers. |
case insensitive string comparisons | Most systems: int strcasecmp() Windows: int strcmpi() or int stricmp() |
writeable argv[] | Many systems allow programs to overwrite theargv[] 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 (gccsupports inline since very long). |
Type | Issues |
---|---|
time_t | Often 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_t | POSIX type not always present on old systems. strlen()and family returns size_t in POSIX |
ssize_t | Commonly used signed version of size_t. Not present onnumerous systems. |
in_addr_t | Not present on many pre-POSIX systems. Functionsthat otherwise use in_addr_t usually use int on those. |
socklen_t | Not present on many pre-POSIX systems. Functionsthat 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_storage | Not present in AIX 4.3 even though ithas getaddrinfo() and other IPv6-ready functions |
off_t | POSIX type for file sizes. Not present on oldersystems. Usually 32 or 64 bit. |
Thanks!