10.1 预处理命令简介

C语言源程序中以 **#** 开头、以换行符结尾的行成为预处理命令。包括:

  1. 宏定义

#define
#undef

  1. 文件包括

#include

  1. 条件编译

#if
#ifdef
#else
#elif
#endif

  1. 其他

#line
#error
#pragma

10.2 宏定义

宏定义分两种,不带参的宏定义带参数的宏定义

10.2.1 不带参的宏定义

#define 标识符 单词串

  1. 通常用大写字母定义宏名。
  2. 宏定义时,如果单词串太长,可以在行尾使用反斜线 \ 续航符。

    1. #define LONG_STRING "this is a very long string that is\
    2. used as an example"
  3. 如果要终止宏的作用域,可以使用 #undef 标识符 命令

    1. #define N 100 //宏定义
    2. int sum() {
    3. ...
    4. }
    5. #undef N //宏取消,下方代码宏不再生效
    6. void main(){
    7. ...
    8. }
  4. 宏可以嵌套定义,不能递归定义 ```c

    define R 2.0

    define PI 3.14159

define L 2PIR //正确

define M M+10 //错误,不可递归定义宏

  1. 5. 程序中字符串常量不作为宏进行宏替换操作
  2. ```c
  3. #define XXX this is a test
  4. printf("XXX"); //输出XXX,而不是this is a test
  1. 宏定义一般以换行结束。不是说不能用分号结尾,而是分号会作为单词串中的一个字符一起进行宏替换,容易引起一行语句两个分号的不必要的错误。
  2. 宏可以被重复定义。
  3. 宏如果是一个表达式,一定要将这个表达式括起来,否则可能会产生错误。 ```c

    define NUM1 10

    define NUM2 20

    define NUM NUM1+NUM2

void main() { int a=2, b=2; a=NUM; //宏替换后为 a=10+20
b=bNUM; //宏替换后为 b=b10+20 printf(“%d %d”,a,b); }

  1. 输出结果为: `60 40` ,而不是 `40 40`
  2. <a name="Mf6rf"></a>
  3. ### 10.2.2 带参数的宏定义
  4. 这样的宏因为定义成一个函数调用的形式,因此也被称为类函数宏。<br />`#define 标识符(参数列表) 单词串`
  5. - 参数列表中的参数只有参数名,**没有数据类型**,之间用逗号隔开
  6. - 单词串是宏的内容文本,也称为**宏体**,其中通常会引用宏的参数
  7. ```c
  8. #define MAX(x,y) ( ( (x) > (y) ) ? (x) : (y) )
  9. void main(){
  10. int a=2,b=3;
  11. a=MAX(a,b)+3; //宏替换为 a=(( (a) > (b) ) ? (a) : (b) )+3
  12. }
  1. 进行上述定义时,不光要将整个宏内容括起来,还要将宏参数也括起来,否则可能引发不必要的错误!!! ```c

    include

define N 3

define Y(n) ((N+1)*n)

void main() { int z=2(N+Y((5+1)));
//如果5+1不打括号,结果为48!因为Y(5+1)被替换为((3+1)
5+1),而Y((5+1))才是Y(6) printf(“%d”, z); } 输出结果 54

  1. **宏的本质是不考虑逻辑的替换!!!**
  2. 2. **定义带参数的宏时,宏名与参数列表的括号之间不能有空格,否则会变成定义一个不带参数的宏!!!**
  3. <br />
  4. <a name="gBKzA"></a>
  5. ## 10.3 文件包含
  6. 文件包含是指,一个C语言源程序通过 `#include` 命令将另一个文件(通常是.c、.cpp或.h文件)的全部内容包含进来。<br />`#include <包含文件名> 或 #include "包含文件名"`
  7. - 使用<>:直接到系统指定的“文件包含目录”去查找被包含的文件。
  8. - 使用"":系统先到当前目录下查找被包含文件,如果没找到,再到直接到系统指定的“文件包含目录”去查。一般地说,使用双引号比较保险。双引号之间还可以指定包含文件的路径,如 `#include "c:\\prg\\p1.h"` 。注意转义字符 `\\`
  9. - 一条包含命令只能指定一个被包含文件。
  10. - 包含文件可以嵌套,即被包含文件中又包含另一个文件。
  11. <a name="eBZfH"></a>
  12. ## 10.4 条件编译
  13. <a name="bxZ9k"></a>
  14. ### 10.4.1 #if … #endif
  15. ```c
  16. #define USA 0
  17. #define ENGLAND 1
  18. #define FRANCE 2
  19. #define ACTIVE_COUNTRY USA
  20. #if ACTIVE_COUNTRY==USA
  21. char *currency="dollar"; //有效
  22. #elif ACTIVE_COUNTRY==ENGLAND
  23. char *currency="pound";
  24. #else
  25. char *currency="france";
  26. #endif
  27. void main(){
  28. float price1, price2, sumprice;
  29. scanf("%f%f", &price1, &price2);
  30. sumprice=price1+price2;
  31. printf("sum=%.2f%s", sumprice, currency);
  32. }
  • elif 和 #else可以没有,但#endif必须有。

  • elif 可以有多个

  • if后面的条件必须是一个常量表达式,通常会用到宏名,条件可以不加括号

#if和#elif常与defiend命令配合使用
**defined(宏名) 或 defined 宏名**

  1. #include<stdio.h>
  2. #define N 30
  3. #if defined (N) //如果定义了宏N
  4. int a=666;
  5. #endif
  6. void main() {
  7. printf("%d",a);
  8. }

输出: 666

10.4.2 #ifdef … #endif

  1. #define INTEGER 122
  2. #ifdef INTEGER
  3. int add(int x, int y) { //有效
  4. return x+y;
  5. }
  6. #else
  7. float add(float x, float y) {
  8. return x+y;
  9. }
  10. #endif
  11. void main(){
  12. #ifdef INTEGER
  13. int a,b,c; //有效
  14. scanf("%d%d",a,b);
  15. printf("%d",add(a.b));
  16. #else
  17. float a,b,c;
  18. scanf("%f%f",a,b);
  19. printf("%f",add(a.b));
  20. #endif
  21. }
  • #ifdef 等价于 #if defined(宏名)
  • #ifdef#else 之间可以加多个 #elif

    10.4.3 #ifndef … #endif

    n可看做是not,顾名思义,没有定义宏,则执行xx,否则执行xx。其余部分跟上面一样。