#define 伪指令
预处理器定义伪指令 指示预处理器将宏的所有后续实例替换为指定的替换标记。
const对象受制于变量的作用域限定规则,而使用#define创建的常量不受约束。- 与
const对象不同,宏的值不会显示在编译器使用的中间 表示 中,因为它们是内联扩展的。 内联扩展使宏值对调试器不可用。
宏可用于编译时常量表达式,例如位域长度 ,而 const对象则不能。
编译器不对宏(包括宏参数)进行类型检查。
类似对象的宏
COUNT 的所有后续实例替换为常量 1000 :#define COUNT 1000int arry[COUNT];int arry[1000];在预处理器的输出中。
COUNT:#define MAX_COUNT COUNT + 100预处理器将 MAX_COUNT 的每个后续实例替换为 COUNT + 100,然后预处理器将其替换为 1000 + 100。
#define a 10
doubl d = a.2
在 中, 预处理器中的对象宏诊断被用于为C和C++编译器提供通用的预处理器接口。 C++11 C99 如果对象类宏名称与其在宏定义中的替换列表之间没有空格,那么 C++11 编译器将发出警告消息。 欲了解更多信息,请参阅 C++11 ( C++11 )中采用的 C99 预处理器功能。
类似函数的宏
与对象类宏相比,函数类宏定义更复杂,它在括号内声明形参的名称,并以逗号分隔。 一个空的形参列表是合法的: 这样的宏可以用来模拟一个不带自变量的函数。 C99 添加了对具有可变自变量数的类似函数的宏的支持。 XL C++支持具有可变参数数量的函数式宏,作为与C兼容的语言扩展,也是 C++11 的一部分。
- 类似函数的宏定义:
- 后跟括号和替换标记中的参数列表的标识。 这些参数嵌入在替换代码中。 空格不能分隔标识 (即宏的名称) 和参数列表的左括号。 必须使用逗号分隔每个参数。
对于可移植性,宏的参数不应超过 31 个。 参数列表可能以省略号 (...) 结尾 作为形参。 在这种情况下,标识
__VA_ARGS__可能会出现在替换列表中。 - 类似于函数的宏调用:
- 后跟以逗号分隔的自变量列表 (括在括号中) 的标识。 参数数目应与宏定义中的参数数目相匹配,除非定义中的参数列表以省略号结尾。 在后一种情况下,调用中的自变量数目应该 匹配或 超过定义中的参数数目。 多余的称为 尾部参数。 一旦预处理器标识了类似函数的宏调用,就会进行参数替换。 替换代码中的参数将替换为相应的参数。 如果宏定义允许尾部自变量,那么它们将与中间逗号合并以替换标识
__VA_ARGS__,就像它们是单个自变量一样。 在自变量替换其在替换代码中的相应参数之前,将完全替换自变量本身中包含的任何宏调用。宏自变量可以为空 (由零个预处理令牌组成)。 例如#define SUM(a,b,c) a + b + c SUM(1,,3) /* No error message. 1 is substituted for a, 3 is substituted for c. */
__VA_ARGS__ 的任何实例。 以下示例对此进行了说明:#define debug(...) fprintf(stderr, __VA_ARGS__)
debug("flag"); /* Becomes fprintf(stderr, "flag"); */- 字符常量
- 在字符串字面值中
- 用括号括起
SUM 定义为具有两个参数 a 和 b 以及替换标记 (a + b):#define SUM(a,b) (a + b)c = SUM(x,y);
c = d * SUM(x,y);c = (x + y);
c = d * (x + y);#define SQR(c) ((c) * (c))c 的括号,以便对表达式进行正确求值,如下所示:y = SQR(a + b);y = ((a + b) * (a + b));y = (a + b * a + b);# 和 ## 运算符的自变量 在 替换类似函数的宏中的参数之前进行转换。
定义后,预处理器标识将保持定义 独立于 语言的作用域限定规则。 宏定义的作用域从定义开始,直到迂到相应的 #undef 伪指令时才结束。 如果没有相应的 #undef 伪指令,那么宏定义的作用域将持续到转换单元结束。
#define x(a,b) x(a+1,b+1) + 4 x(20,10) x(20+1,10+1) + 4而不是尝试在自身内部扩展宏 x 。 在扩展宏 x 之后,它是对函数 x()的调用。
debug 的所有实例:#define debug仅当第二个预处理器 #define 伪指令前面有预处理器 #undef 伪指令时,才能使用第二个预处理器 #define 伪指令来更改定义的标识或宏的定义。 #undef 伪指令会使第一个定义无效,以便可以在重新定义中使用同一标识。
在程序文本中,预处理器不会扫描 宏定义,取消定义宏或宏调用的 注释,字符常量或字符串常量。
以下示例程序包含两个宏定义以及引用了这两个已定义宏的宏调用:
/**This example illustrates #define directives.**/
void printf(const char*, ...);
#define SQR(s) ((s) * (s))
#define PRNT(a,b) \
printf("value 1 = %d\n", a); \
printf("value 2 = %d\n", b)
int main(void)
{
int x = 2;
int y = 3;
PRNT(SQR(x),y);
return(0);
}经过 预处理后,此程序将替换为等效于以下内容的代码:
void printf(const char*, ...);
int main(void)
{
int x = 2;
int y = 3;
printf("value 1 = %d\n", ( (x) * (x) ) );
printf("value 2 = %d\n", y);
return(0);
}value 1 = 4
value 2 = 3
变量宏扩展是指与具有可变自变量数的宏相关的 C99 和 C++03 的两个扩展。 一个扩展是用于将变量参数标识从 __VA_ARGS__ 重命名为用户定义的标识的机制。 当未指定任何变量自变量时,另一个扩展提供了一种方法来除去变量宏中的悬空逗号。 这两个扩展都已实现,以便于移植使用 GNU C 和 C++开发的程序。
__VA_ARGS__。 宏 debug 的第一个定义说明了 __VA_ARGS__的通常用法。 第二个定义显示使用标识 args 代替 __VA_ARGS__。#define debug1(format, ...) printf(format, ## __VA_ARGS__)
#define debug2(format, args ...) printf(format, ## args)
| 调用 | 宏扩展的结果 |
|---|---|
debug1("Hello %s/n", "World"); |
printf("Hello %s/n", "World"); |
debug2("Hello %s/n", "World"); |
printf("Hello %s/n", "World"); |
## 的逗号在函数宏定义中的变量自变量标识之前,那么预处理器将除去尾部逗号。
在 中,变量宏功能和关于空宏参数的更改是从 预处理器中采用的,为C和C++编译器提供了一个通用的预处理器接口。 C++11 C99 C++11中支持变量宏和空宏参数。 有关更多信息,请参阅 C++11 中采用的 C99 预处理器功能部件 (C++11)。