home
table of contents
Programming
July 2004
email

Writing Portable Code in C

The standard advice for writing portable code is to isolate non-portable code into its own module(s). If you are using C you can go a bit further than simple isolation.

We begin by creating an include file called platform.h (pick your own name for it.) In effect, this include file is a little database containing information about platform dependent code.

Platform dependent modules (and only platform dependent modules) include platform.h. The general idea is to set things up so that you can build programs for each supported platform with a simple make that specifies the platform on the command line, e.g., (if I recall the syntax correctly)

	make foo -DLINUX
Label each required platform dependent property and functionality in the program with a preprocessor variable, e.g., NEED_FOOBAR. In the modules that have platform dependencies you create definitions for the “need” variables for the properties and functionality actually needed. Corresponding to NEED_FOOBAR is a macro in platform.h called FOOBAR.
#define NEED_FOOBAR
....
#include "platform.h"
....
/* code using FOOBAR */
The idea, then, is that in platform.h FOOBAR will be defined using the platform specific variant if NEED_FOOBAR is defined.

Now it happens that platforms fall into families. Thus, for example, there are the BSD unix, SysV unix, DOS, windows, VMS, and posix families. Most of the variation is across family; accordingly it is useful in the platform sections to define which family (ies) a platform belongs to.

The specific dependency code is then defined within family sections, e.g.:

#if defined OS_LINUX
#define FAMILY_SYSV	1
#define FAMILY_POSIX	1
...
#elif defined OS_386BSD
#define FAMILY_BSD	1
...
#if defined FAMILY_SYSV
...
#ifdef NEED_FOOBAR
#define FOOBAR the_sky(3.14159265)
#endif
...
#endif
Your actual implementation needs to be a bit more elaborate than the above. Advantages of the scheme include: dependencies are clearly delimited; the “database” is portable from one program to another; porting is simplified because most platforms will belong to already processed families; and the actual kinds of dependencies are clearly spelled out. Disadvantages are that it can be cumbersome and that it takes initial work to set up.

Incidentally it helps a good deal in writing highly portable code if you stay within the boundaries of posix compliance. Most ‘big’ OS’s offer posix compliance.


This page was last updated July 1, 2004.

home
table of contents
Programming
July 2004
email