Many useful system header files are in different places in different systems, or they define different symbols. We will assume henceforth that the application has been developed on a BSD-like Unix and must be ported to a System V-like Unix or VMS or a Unix-like system with header files that comply with the Standard.
In the following sections, we show how to handle the most simple cases that arise in practice. Some of the code that appears below was derived from the header file Xos.h which is part of the X Window System distributed by MIT. We have added changes, e.g., to support VMS.
Many header files are unprotected in many systems, notably those derived from BSD version 4.2 and earlier. By "unprotected" we mean that an attempt to include a header file more than once will either cause compilation errors (e.g., due to recursive or nested includes) or, in some implementations, warnings from the preprocessor stating that symbols are being redefined. It is good practice to protect header files.
ctype.h provides almost the same functionality on all systems, except that some symbols must be renamed.
#ifdef SYSV # define _ctype_ _ctype # define toupper _toupper # define tolower _tolower #endif
Under Sys V, toupper and tolower are also defined and will check the validity of their arguments and perform the conversion only if necessary. Under BSD-derived systems, one must normally remember to check the validity of the arguments. The following solution might be acceptable to most:
#ifdef SYSV # define TOUPPER(c) toupper(c) #else /* !SYSV */ # define TOUPPER(c) (islower(c)?toupper(c):(c)) #endif
The definitions in <ctype.h> are not portable across character sets.
Many files that a BSD-like system expects to find in the sys directory are placed in /usr/include in System V. Other systems, such as VMS, do not even have a sys directory. (9)
The symbols used in the open function call are defined in different header files in the two types of systems:
#ifdef SYSV # include <fcntl.h> #else # include <sys/file.h> #endif
In some systems, e.g., BSD 4.3 and SunOS, it does not make a difference which one is used because both define the O_xxxx symbols.
The semantics of the error number may differ from one system to another and the list may differ as well (e.g., BSD systems have more error numbers than System V). Some systems, e.g., SunOS, define the global symbol errno which will hold the last error detected by the run-time library. This symbol is not declared in most systems, although it is required by the Standard that such a symbol be defined (see section 4.1.3 of the Standard [13]). It is, of course, available in all Unix implementations.
The most portable way to print error messages is to use perror.
System V has more definitions in this header file than BSD-like systems. The corresponding library has more functions as well. This header file is unprotected under VMS and Cray, and in that case we must do it ourselves:
#if defined(CRAY) || defined(VMS) # ifndef __MATH__ # define __MATH__ # include <math.h> # endif #endif
Some systems cannot be treated as System V or BSD, but are really special cases, as one can see in the following:
#ifdef SYSV # ifndef SYSV_STRINGS # define SYSV_STRINGS # endif #endif#ifdef _STDH_ /* ANSI C Standard header files */ # ifndef SYSV_STRINGS # define SYSV_STRINGS # endif #endif
#ifdef macII # ifndef SYSV_STRINGS # define SYSV_STRINGS # endif #endif
#ifdef vms # ifndef SYSV_STRINGS # define SYSV_STRINGS # endif #endif
#ifdef SYSV_STRINGS # include <string.h> # define index strchr # define rindex strrchr #else # include <strings.h> #endif
As one can easily observe, System V-like Unix systems use different names for index and rindex and place them in different header files. Although VMS supports better System V features, it must be treated as a special case.
When using time.h, one must also include types.h. The following code does the trick:
#ifdef macII # include <time.h> /* on a Mac II we need this one as well */ #endif #ifdef SYSV # include <time.h> #else # ifdef vms # include <time.h> # else # ifdef CRAY # ifndef __TYPES__ /* it is not protected under CRAY */ # define __TYPES__ # include <sys/types.h> # endif # else # include <sys/types.h> # endif /* of ifdef CRAY */ # include <sys/time.h> # endif /* of ifdef vms */ #endif
The above is not sufficient in order for the code to be portable since the structure that defines time values is not the same in all systems. Different systems have vary in the way time_t values are represented. The Standard, for instance, only requires that it be an arithmetic type. Recognizing this difficulty, the Standard defines a function called difftime to compute the difference between two time values of type time_t, and mktime which takes a string and produces a value of type time_t.
In some systems the definitions in both header files are contradictory. For instance, the following will produce compilation errors, e.g., under VMS:
#include <varargs.h> #include <stdio.h>
This is because <stdio.h> includes <stdarg.h> which in turn redefines all the symbols (va_start, va_end, etc.) in <varargs.h>. This is incorrect behavior because Standard header files should not include other Standard header files. Furthermore, the method used in <varargs.h> for defining variadic functions is incompatible with the Standard (see section 11.2.3 for more information on variadic functions).
The solution we adopt is to always include <varargs.h> last and not to define in the same module both functions that use <varargs.h> and functions that use the ellipsis notation.
This one is lacking in some systems (e.g., Altos and Xenix). HP-UX does define it but one must use macros to access the fields of the wait struct, instead of using the names of the fields. The wait struct uses bit-fields and if the platform does not define it one must do it oneself and care must be taken with respect to byte ordering (see Byte ordering in section 11.1).
contents
Unix Flavors: System V and BSD
Run-time Library