What should you use to compile a C program on many different platforms - computer CPU'S and operating system?

To write C code to cater for different target platforms we use a combination of C standard library code, conditional compilation. All C standard library code is cross platform and we should use it as much as possible. All third-party libraries should be as generic as possible. If we must use system-specific code or libraries, then we need to use conditional compilation.
Conditional compilation occurs during the preprocessing stage. The preprocessor (also known as the precompiler) prepares our code for compilation. Note that the compiler doesn't compile our source code, it actually compiles the code output by the preprocessor, also known as the intermediate source. The intermediate source files are usually deleted after compilation is complete, however your compiler will include a switch which allows these files to be retained so that you can see the actual code that was compiled by the compiler.

Preprocessing primarily processes all lines that begin with the # symbol. Thus a #include directive tells the preprocessor to import the named header into the intermediate source (the imported file is also preprocessed). The preprocessor also creates a table of macro symbols. Some of these symbols are passed via the command line however others are macro definitions (#define directives) embedded in the code itself. These definitions are stripped out of the intermediate source, but when a macro symbol is encountered in your code, the stored definition allows the preprocessor to generate the appropriate C code in it place. Note that the compiler never sees the macro -- it only sees the expanded code -- hence the compiler cannot help you to debug macros defined as functions.

In other words, the preprocessor allows us to generate a C source file that will change depending on which macros are currently defined (or not defined, as the case may be). One the more common uses of conditional compilation is to cater for differences between debug and non-debug builds, as shown by this example:

#ifndef NDEBUG

If the NDEBUG macro is not defined then we are compiling a debug build, thus the code in the ellipses (...) will be included in the intermediate source. But if NDEBUG is defined, then we are compiling a non-debug build and the code will not be included in the intermediate source. The NDEBUG macro must be defined via the command line. Often, the source will also include a macro such that when NDEBUG is not defined, a DEBUG macro is defined instead, thus allowing us to use the more intuitive #ifdef DEBUG directive instead of #ifndef NDEBUG. However, NDEBUG is part of the C standard and should always be examined before defining any other non-standard debug macros such as DEBUG.

Platform-dependent code makes use of platform-dependent macros. These are typically defined internally by the compiler itself, however some compilers cater for two or more platforms and we can supply the specific macros we require for a given build via the command line. Visual Studio is an example of this because it must cater for 16-bit, 32-bit and 64-bit Windows platforms as well Itanium, ARM and other platforms. To define the appropriate macro(s) we simply choose the target platform in the appropriate build properties of the project:


Projects can have two or more builds associated with them. Each build environment creates a unique set of macros that allow us to generate machine code for all supported platforms from the same source. The source may also include code for other platforms such as Unix/Linux, but so long as that code is conditionally compiled with the appropriate macros, Visual Studio will simply ignore it because those macros are not defined by Visual Studio. Similarly, when the source is compiled by a compiler that doesn't support the Windows platforms, the Windows-specific code will be ignored by that compiler.