1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
// #define #include #ifdef #else #endif #ifndef #if #elif #line #error #pragma // sqrt() atan() atan2() exit() atexit() assert() memcpy() memmove() va_start() // va_arg() va_copy() va_end() // C预处理器的更多功能 // 类函数宏和条件编译 // 内联函数 // C库概述和其中一些方便的函数 #include <stdio.h> #define TWO 2 // 注释 预处理语句以#开头 /*反斜杠可以把这个定义延续到下一行(反斜杠后页面显示有点问题,所以注释了) #define OW "Consistency is the last refuge of the unimagina\ tive. -Oscar Wilde" */ #define FOUR TWO*TWO #define PX printf("X is %d\n", x) #define FMT "X is %d \n" int main(int argc, char const *argv[]) { // 每个#define行(逻辑行)由三部分组成。 // 1.#define本身 // 2.所选择的缩略词(宏macro) 本例中的宏代表值,称为对象宏(object-like macro) C还有类函数宏 // 3.第三部分称为替换列表或主体 // 预处理器在程序中发现宏以后,会用实体代替该宏(有一种例外) int x = TWO; PX; x = FOUR; printf(FMT, x); printf("%s\n", OW); printf("TWO:OW\n"); /* 宏可以替换常量、表达式、字符串等 X is 2 X is 4 //宏不进行任何计算 计算是在替换以后 运行代码后 2*2得出 Consistency is the last refuge of the unimaginative. -Oscar Wilde TWO:OW //引号中会被认为是字符串常量,不进行替换 */ return 0; } // 类函数宏 #include <stdio.h> // SQUARE为宏标识符 括号中的X为宏的参数 X*X为替换列表 #define SQUARE(X) X*X #define PR(X) printf("The result is %d.\n", X); int main(int argc, char const *argv[]) { int z; z = SQUARE(x); PR(z); z= SQUARE(2); PR(z); PR(SQUARE(x+2)); PR(100/SQUARE(2)); PR(SQUARE(++x)); /* The result is 16. The result is 4. The result is 14. //替换成 x+2*x+2=4+2*4+2 (宏不进行计算、只进行替换) The result is 100. //100/2*2 The result is 36. //++x*++x 进行了两次增量后 6*6=36,有些编译器:5*6=30 */ return 0; } //类宏函数引号中使用宏参数"string" #PARAM "string" #include <stdio.h> #define PR(X) printf("the square of " #X " is %d\n", ((X)*(X))); int main(int argc, char const *argv[]) { int y = 5; PR(y); PR(2 + 4); /* ((X)*(X)))可以避免上例中的SQUARE(x+2) 100/SQUARE(2)但是不能避免SQUARE(++x) the square of y is 25 the square of 2 + 4 is 36 */ //使用宏和函数的抉择(时间和空间的抉择) //调用宏20次,会把20行代码插入程序中(浪费空间) //调用函数20次,只有一份函数拷贝,但程序的控制会转移到函数中随后返回调用程序(浪费时间) //宏有一个优点,不检查变量类型(宏处理替换字符串,而不是实际值) //总结:很短的函数、比较追求性能,可以使用宏(但是需要注意宏是否会引起重大差异,如上例) //c99还提供了内联函数(跟类函数宏效果类似) //inline void test() 增加inline关键字即可 return 0; } //do while在类宏函数中的用法 #include <stdio.h> #define TEST(a,b) a++;b++; #define TEST1(a,b) \ do { \ a++;b++; \ } while(0) \ int main(int argc, char const *argv[]) { int a = 1; int b = 2; if (1==1) //如果这里使用TEST(a,b);会编译出错,因为if条件没有使用大括号但是后面跟了a++;b++; //所以,很多类宏函数通常使用do{}while(0)写法来达到更好的兼容性 TEST1(a,b); else int c = 3; printf("%d %d\n", a, b); return 0; } //预处理的粘合剂:##运算符 #include <stdio.h> #define XNAME(n) x ## n #define PRINT_XN(n) printf("x" #n " = %d\n", x ## n); int main(int argc, char const *argv[]) { int XNAME(1) = 14; int XNAME(2) = 20; PRINT_XN(1); PRINT_XN(2); /* x1 = 14 x2 = 20 */ return 0; } //可变宏:...和__VA_ARGS__ #include <stdio.h> #include <math.h> #define PR(X, ...) printf("Message " #X ": " __VA_ARGS__); int main(int argc, char const *argv[]) { double x = 48; double y; y = sqrt(x); PR(1, "x=%g\n", x); PR(2, "x=%.2f,y=%.4f\n", x, y); /* Message 1: x=48 //替换后printf("Message " "1" ": " "x=%g\n", x) Message 2: x=48.00,y=6.9282 */ return 0; } // #include文件包含 #include <stdio.h> int main(int argc, char const *argv[]) { /* #include <stdio.h> //搜索系统目录 #include "test.h" //搜索当前工作目录 #include "/usr/local/test.h" //搜索/usr/local目录 具体搜索哪些目录,不同编译器可能有不同结果 */ return 0; } #include <stdio.h> #define LIMIT 400 //取消LIMIT定义,如果之前没有定义LIMIT,这句语句也是合法的,不确定的情况下可以先取消再定义更为保险 #undef LIMIT #ifdef MAVIS #include "horse.h" //如果已经用#define定义了MAVIS,则执行这里的指令 #define STABLES 5 #else #include "cow.h" //如果没有用#define定义了MAVIS,则执行这里的指令 #define STABLES 15 #endif #define JUST_CHECKING #define LIMIT 4 int main(int argc, char const *argv[]) { /* 不同的工作环境使用不同的C程序或C库包 改变一些#define宏的值后,这些代码就可以被移植到另一个系统 #undef指令取消前面的#define定义 __DATE__和__FILE__等预定义宏,不能被取消 #if #ifdef #ifndef #else #elif #endif指令可用于选择什么情况下编译哪些代码 #line指令用于重置行和文件信息 #error指令用于给出错误信息 #pragma指令用于向编译器发出提示 */ int i; int total = 0; for (int i = 1; i < LIMIT; ++i) { total += 2 * i * i + 1; #ifdef JUST_CHECKING //代码块中也可以使用 printf("i=%d running total=%d\n", i, total); #endif } printf("Grand total=%d\n", total); return 0; } |