C预处理器是C语言、C++语言的预处理器。用于在编译器处理程序之前预扫描源代码,完成头文件的包含, 宏扩展, 条件编译(英语:conditional compilation), 行控制(line control)等操作。
C语言标准规定,预处理是指前4个编译阶段(phases of translation)。
用于包含另一个文件:
#include <stdio.h>int main(void){ printf("Hello, world!n"); return 0;}C预处理器是C语言、C++语言的预处理器。用于在编译器处理程序之前预扫描源代码,完成头文件的包含, 宏扩展, 条件编译(英语:conditional compilation), 行控制(line control)等操作。
C语言标准规定,预处理是指前4个编译阶段(phases of translation)。
用于包含另一个文件:
#include <stdio.h>int main(void){ printf("Hello, world!n"); return 0;}if-else指令包括#if, #ifdef, #ifndef, #else, #elif and #endif .
#if VERBOSE >= 2 print("trace message");#endif#ifdef __unix__ /* __unix__ is usually defined by compilers targeting Unix systems */# include <unistd.h>#elif defined _WIN32 /* _WIN32 is usually defined by compilers targeting 32 or 64 bit Windows systems */# include <windows.h>#endif#if !(defined __LP64__ || defined __LLP64__) || defined _WIN32 && !defined _WIN64 // we are compiling for a 32-bit system#else // we are compiling for a 64-bit system#endif
有两种宏:
#define <identifier> <replacement token list> // object-like macro#define <identifier>(<parameter list>) <replacement token list> // function-like macro, note parameters
宏定义可以用#undef取消:
#undef <identifier> // delete the macro
__FILE__ 与 __LINE__, 扩展为当前文件与行号。例如:
// debugging macros so we can pin down message origin at a glance#define WHERESTR ": "#define WHEREARG __FILE__, __LINE__#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)//... DEBUGPRINT("hey, x=%dn", x);C或C++语言标准定义了宏: __STDC__, __STDC_VERSION__, __cplusplus,__DATE__,__TIME__,__func__等。
#运算符(Stringification Operator)把随后的token转化为C语言的字符串。
#define str(s) #sstr(p = "foon";) // outputs "p = "foo\n";"str(n) // outputs "n"
即使#运算符后面的是另一个宏名,这个宏名将不会被宏展开,而是按照字面值被当作一个字符串。因此,如果需要#运算符后面的宏名做宏展开,需要使用两层宏的嵌套使用,其中外层的宏展开时也一并把#运算符后面的宏名做宏展开。例如:
#define xstr(s) str(s)#define str(s) #s#define foo 4str (foo) // outputs "foo"xstr (foo) // outputs "4"
##运算符(Token Pasting Operator)连接两个token为一个token.
#define DECLARE_STRUCT_TYPE(name) typedef struct name##_s name##_tDECLARE_STRUCT_TYPE(g_object); // Outputs: typedef struct g_object_s g_object_t;
##运算符左侧或右侧如果是另一个宏名,这个宏名将不会被宏展开,而是按照字面值被当作一个token。因此,如果需要##运算符左右的宏名做宏展开,需要使用两层宏的嵌套使用,其中外层的宏展开时也一并把##运算符左右的宏名做宏展开。
#error "error message"#warning "warning message"
#pragma指令提供了编译器特定的预处理功能。