C语言的宏之明示常量

逃离我推掉我的手 2023-02-20 12:20 53阅读 0赞

C语言的宏之明示常量

在这里插入图片描述

引言

预处理功能是C语言特有的功能,它是在对源程序正式编译前由预处理程序完成的,程序员在程序中用预处理命令来调用这些功能。

宏定义可以带有参数,宏调用时是以实参代换形参,而不是“值传送”。

为了避免宏代换时发生错误,宏定义中的字符串应加括号,字符串中出现的形式参数两边也应加括号。

文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。

条件编译允许只编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率。

使用预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计。

明示常量(符号常量)

#define预处理指令和其他预处理指令一样,以#号作为一行的开始。ANSI和后来的标准都允许#号前有空格或制表符,而且还允许在#和指令的其余部分之间有空格。但是旧版的C要求指令从一行最左边开始,而且#和其余部分之间不能有空格。指令可以出现在源文件的任何地方,其定义从质量出现的地方到该文件末尾有效。我们大量使用#define指令来定义明示常量(也叫符号常量)。

示例:

  1. /* preproc.c -- simple preprocessor examples */
  2. #include <stdio.h>
  3. #define TWO 2 /* you can use comments if you like */
  4. #define OW "Consistency is the last refuge of the unimagina\ tive. - Oscar Wilde" /* a backslash continues a definition */
  5. /* to the next line */
  6. #define FOUR TWO*TWO
  7. #define PX printf("X is %d.\n", x)
  8. #define FMT "X is %d.\n"
  9. int main(void)
  10. {
  11. int x = TWO;
  12. PX; /*宏展开后变成 printf("X is %d.\n", x); */
  13. x = FOUR;
  14. printf(FMT, x);
  15. printf("%s\n", OW);
  16. printf("TWO: OW\n");
  17. return 0;
  18. }

每行#define(逻辑行)都由3部分组成。第一部分是#define指令本身。第二部分是选定的缩写,也成为宏,宏的名称必须遵循C变量的命名规则。第三部分(指令行的其余部分)称为**替换列表或替换体。一旦预处理器在程序中找到宏的实例后,就会用替换体代替该宏。从宏编程最终替换文本的过程称为宏展开。**注意,可以在#define行使用标准C注释。

宏可以代表任何字符串,甚至可以表示整个C表达式。

宏定义还可以包含其他宏(一些编译器不支持这种嵌套功能)。

  1. printf(FMT, x);

变成了

  1. printf("X is %d.\n", x);

一般而言,预处理器发现程序中的宏后,会用宏等价的替换文本进行替换。如果替换的字符串中还包含宏,则继续替换这些宏。唯一例外的是双引号汇总的宏。因此,下面的语句:

  1. printf("TWO: OW\n");

打印的是

  1. TWO: OW

而不是

  1. 2:"Consistency is the last refuge of the unimaginative. - Oscar Wilde

宏定义的几点说明1

  1. 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的替换。字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。
  2. 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换。
  3. 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。
  4. 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。
  5. 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换(一些编译器不支持这种嵌套功能)。
  6. 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。
  7. 可用宏定义表示数据类型,使书写方便。例如:

    define UINT unsigned int

在程序中可用UINT作变量说明:

  1. UINT a, b;

应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。

结语

那么,何时使用字符常量?对于绝大部分数字常量,应该使用字符常量。如果在算式中用字符常量代替数字,常量名能更清楚地表达该数字的含义。如果是表示数组大小的数字,用符号常量更容易改变数组的大小和循环次数。如果数字是系统代码(如,EOF),用符号常量表示的代码更容易移植。助记、易更改、可移植,这些都是符号常量很有价值的特性。


参考资料

  1. 史蒂芬・普拉达. C Primer Plus (第6版) 中文版[M]. 人民邮电出版社, 2016.

  1. C语言宏定义—来源 ↩︎

发表评论

表情:
评论列表 (有 0 条评论,53人围观)

还没有评论,来说两句吧...

相关阅读

    相关 RustC语言

    宏可以说是C语言的双刃剑,C语言中的宏提供诸多便利,但同时也带来了很多陷阱。 Rust保留了宏的概念,但是比C语言的宏有了不少改进。 宏与函数的区别 无论在Rust中

    相关 C语言常量

    笔记 【1】基本数据类型的常量(掌握) (1)整型常量 常量是指在程序运行期间其数值不会发生变化的数据。整型常量通常简称为整数。 整数可以是十进制数、八进制数和十

    相关 C语言

    6、\define预处理指令可以用来定义宏 7、宏可以用来给数字起名字 8、定义宏的时候要把宏名称写在\define预处理指令后,宏名称后写它所代表的数字 9、宏名称通常