Preprocessor
When C (and Objective-C) code files are compiled, they are first sent through an initial program, called the preprocessor, before being sent to the compiler proper. Lines that begin with a # character are directives to the preprocessor. Using preprocessor directives, you can:
- Import the text of a file into one or more other files at a specified point.
- Create defined constants.
- Conditionally compile code (compile or omit statement blocks depending on a condition).
Including Files
The following line:
#include "HeaderFile.h"
causes the preprocessor to insert the text of the file HeaderFile.h into the file being processed at the point of the #include line. The effect is the same as if you had used a text editor to copy and paste the text from HeaderFile.h into the file being processed.
If the included filename is enclosed in quotation marks (""):
#include "HeaderFile.h"
the preprocessor will look for HeaderFile.h in the same directory as the file being compiled, then in a list of locations that you can supply as arguments to the compiler, and finally in a series of system locations.
If the included file is enclosed in angle brackets (<>):
#include <HeaderFile.h>
the preprocessor will look for the included file only in the standard system locations.
#define
#define is used for textual replacement. The most common use of #define is to define constants, such as
#define MAX_VOLUME 11
The preprocessor will replace every occurrence of MAX_VOLUME in the file being compiled with an 11. A #define can be continued on multiple lines by placing a backslash (\) at the end of all but the last line in the definition.
A frequently used pattern is to place the #define in a header file, which is then included by various source files. You can then change the value of the constant in all the source files by changing the single definition in the header file. The traditional C naming convention for defined constants is to use all capital letters. A traditional Apple naming convention is to begin the constant name with a k and CamelCase the rest of the name:
#define kMaximumVolume 11
You will encounter both styles, sometimes in the same code.
Conditional Compilation
The preprocessor allows for conditional compilation:
#if condition statements #else otherStatements #endif
Here, condition must be a constant expression that can be evaluated for a truth value at compile time. If condition evaluates to true (non-zero), statements are compiled, but otherStatements are not. If condition is false, statements are skipped and otherStatements are compiled.
The #endif is required, but the #else and the alternative code are optional. A conditional compilation block can also begin with an #ifdef directive:
#ifdef name statements #endif
The behavior is the same as the previous example, except that the truth value of #ifdef is determined by whether name has been #define’d.
One use of #if is to easily remove and replace blocks of code during debugging:
#if 1 statements #endif
By changing the 1 to a 0, statements can be temporarily left out for a test. They can then be replaced by changing the 0 back to a 1.
#if and #ifdef directives can be nested, as shown here:
#if 0 #if 1 statements #endif #endif
In the preceding example, the compiler ignores all the code, including the other compiler directives, between the #if 0 and its matching #endif. statements are not compiled.
If you need to disable and re-enable multiple statement blocks, you can code each block like this:
#if _DEBUG statements #endif
The defined constant _DEBUG can be added or removed in a header file or by using a –D flag in the compile command.
printf
Input and output (I/O) are not a part of the C language. Character and binary I/O are handled by functions in the C standard I/O library.
To use the functions in the standard I/O library, you must include the library’s header file in your program:
#include <stdio.h>
The only function covered here is printf, which prints a formatted string to your terminal window (or to the Xcode console window if you are using Xcode). The printf function takes a variable number of arguments. The first argument to printf is a format string. Any remaining arguments are quantities that are printed out in a manner specified by the format string:
printf( formatString, argument1, argument2, ... argumentN );
The format string consists of ordinary characters and conversion specifiers:
- Ordinary characters (not %) in the format string are sent unchanged to the output.
- Conversion specifiers begin with a percent sign (%). The letter following the % indicates the type of argument the specifier expects.
- Each conversion specification consumes, in order, one of the arguments following the format string. The argument is converted to characters that represent the value of the argument, and the characters are sent to the output.
The only conversion specifiers used in this book are %d for char and int, %f for float and double, and %s for C strings. C strings are typed as char*.
Here is a simple example:
int myInt = 9; float myFloat = 3.145926; char* myString = "a C string"; printf( "This is an integer: %d, a float: %f, and a string: %s.\n", myInt, myFloat, myString );
The result of the preceding example is
This is an Integer: 9, a float: 3.145926, and a string: a C string.
If the number of arguments following the format string doesn’t match the number of conversion specifications, printf ignores the excess arguments or prints garbage for the excess specifications.