#define
DESCRIPTION: 定义一个宏
NOTE:
1 所有用于表达式求值的宏定义都应该对参数加上括号,避免在使用宏时,由于参数中操作符或邻近的操作符之间不可预料的相互作用
2 宏与类型无关
USAGE1: #define name [stuff]
EXPLANATION: 当符号出现在这条指令后面时, 预处理就会把它替换成stuff
COMMAND: gcc -E main.c -o main.i
EXAMPLES:
#define reg register
#define do_forever for(;;)
#define CASE break;case
USAGE2: #define name(parameter-list) [stuff]
ATTENTION: parameter-list是一个由都好分隔的符号列表,它们可能出现在stuff中。
参数列表的左括号必须与name紧邻,如果两者之间有空白存在,参数列表就会被解释为stuff的一部分;
将宏参数插入到字符串常量中
SKILL1: 邻近字符串自动链接的特性
#define PRINT(FORMAT, VALUE) \
printf("The value is " FORMAT "\n", VALUE)
PRINT("%d", 5)预处理后的结果为: printf("The value is " "%d" "\n", 5) 等价于 printf("The value is %d \n", 5)
SKILL2: 使用预处理器把一个宏参数转换为一个字符串
#define PRINT(FORMAT, VALUE) \
printf("The value of " #VALUE \
" is " FORMAT "\n", VALUE)
PRINT("%d", x + 3) 预处理后的结果为: printf("The value of " "x + 3" " is " "%d" "\n", x + 3) 等价于 printf("The value of x + 3 is %d\n", x + 3)
SKILL3:##将它两边的符号连接成一个符号, ##左右两边有无空格效果一样
#define ADD_TO_SUM( sum_number, value) \
sum ## sum_number += value
ADD_TO_SUM(5, 5)预处理后的结果为: sum5 += 5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#undef
DESCRIPTION: 移除一个宏定义
USAGE: #undef name
命令行定义:
gcc -DNAME -E main.c -o main.i 定义一个宏NAME 等同于 #define NAME
gcc -DAGE=25 -E main.c -o main.i 定义一个宏AGE 25 等同于 #define AGE 25
gcc -DNAME="\"John\"" -E main.c -o main.i 定义一个宏NAME "John" 等同于 #define NAME "John"
gcc -DNAME -UNAME -E main.c -o main.i 相当于未定义宏 等同于 #define NAME #undef NAME
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if constant-expression
statements
#endif
DESCRIPTION: 条件编译
EXPLANATION: constant-expression 常量表达式 -> 字面量或者由#define定义的符号
#if constant-expression
statements
#elif constant-expression
statements
#else
statements
#endif
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
DESCRIPTION: 判断是否定义
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if defined( OS_UNIX )
#ifdef OPTION1
unix_version_of_option1();
#endif
#ifdef OPTION2
unix_version_of_option2();
#endif
#elif defined( OS_MSDOS )
#ifdef OPTION2
msdos_version_of_option2();
#endif
#endif
DESCRIPTION: 嵌套指令
#ifdef OPTION1
lengthy code for option1;
#else
lengthy code for alternative;
#endif /*OPTION1*/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include
DESCRIPTION: 文件包含
USAGE:#include <filename>
#include "filename"
#include "/usr/lib/filename"
EXPLANATION: <filename> 和 "filename" 的区别: 前者在编译器指定的位置查找函数库头文件,
后者先在当前目录下查找指定文件,如果未找到的情况下再去编译器指定的位置查找文件
"usr/lib/filename" 使用绝对路径指定文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifndef _HEADERNAME_H
#define _HEADERNAME_H 1
#endif
DESCRIPTION: 防止文件出现多次包含的情况发生
EXAMPLES:
main.h
#ifndef _MAIN_H
#define _MAIN_H 1
...
#endif
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#error
DESCRIPTION: 生成错误信息
EXAMPLES:
#if defined( OPTION_A )
stuff needed option A
#elif defined( OPTION_B )
stuff needed option B
#elif defined( OPTION_C )
stuff needed option C
#else
#error No option selected
#endif /* 如果未定义OPTION_A OPTION_B OPTION_C 则预处理报错 No option selected */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#line
USAGE: #line number [string]
DESCRIPTION: 修改__LINE__符号的值, 加上可选部分将修改__FILE__的值
EXPLANATION: number 为下一行输入的行号 可选字符串[string] 将修改__FILE__的值
EXAMPLES:
main.c
1 #include <stdio.h>
2
3 #line 5 "TEST"
4
5 void main() {
6 printf("%d\n", __LINE__);
7 printf("%s\n", __FILE__);
8 }
#line 5 "TEST"
此时第四行的行号修改为第5行,所以此时__LINE__的值为7
此时__FILE__的值为"TEST"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#progma
DESCRIPTION: 用于支持因编译器而异的特性, 不可移植