Preprocessor Arithmetic

Preprocessor macro replacement expressions are textual and do not utilize types. Unless they are part of the controlling expression to the inclusion directives (discussed below), macros are not evaluated by the preprocessor. Once macros have been textually expanded and preprocessing is complete, the expansion forms a C expression which is evaluated by the code generator along with other C code. Tokens within the expanded C expression inherit a type, with values then subject to integral promotion and type conversion in the usual way.

If a macro is part of the controlling expression to a conditional inclusion directive (#if or #elif), the macro must be evaluated by the preprocessor. The result of this evaluation is often different to the C-domain result for the same sequence. The preprocessor assigns sizes to literal values in the controlling expression that are equal to the largest integer size accepted by the compiler, as specified by the size of intmax_t defined in <stdint.h>.

For the MPLAB XC8 C compiler, this size is 32 bits, unless you are compiling for a PIC18 device with C99 in which case it is 64 bits.

The following code might not work as expected. The preprocessor will evaluate MAX to be the result of a 32-bit multiplication, 0xF4240. However, the definition of the long int variable, max, will be assigned the value 0x4240 (since the constant 1000 has a signed int type, and therefore the C-domain multiplication will also be performed using a 16-bit signed int type).

#define MAX 1000*1000
...
#if MAX > INT16_MAX       // evaluation of MAX by preprocessor
    long int max = MAX;   // evaluation of MAX by code generator
#else
    int max = MAX;        // evaluation of MAX by code generator
#endif

Overflow in the C domain can be avoided by using a constant suffix in the macro (see Constant Types and Formats). For example, an L after a number in a macro expansion indicates it should be interpreted by the C compiler as a long, but this suffix does not affect how the preprocessor interprets the value, if it needs to evaluate it.

For example, the following will evaluate to 0xF4240 in C expressions.

#define MAX 1000*1000L