C MACRO评估

时间:2018-08-09 11:42:54

标签: c gcc c-preprocessor

我想声明一个静态分配的数组。 让我们看一下以下代码:

#define MAX(a,b) ((a)>(b)?(a):(b))
#define FAST            16
#define SLOW            6
#define MAX_NUM         MAX(FAST,SLOW)
U8*   pBuffers[MAX_NUM];

何时由GCC编译器评估MAX_NUM(FAST和SLOW是常量)? 我想确保MAX_NUM是常量,并作为编译的一部分或由预处理程序进行评估。

3 个答案:

答案 0 :(得分:2)

启动编译器时,将依次执行以下阶段:

  • 预处理:它管理#define,#ifdef / #endif ...
  • 代码生成:它生成可在目标CPU上运行的机器代码
  • 优化:根据用户选项进行优化

预处理阶段,预处理器将例如用以下行“替换”您的行:

U8*   pBuffers[MAX(FAST,SLOW)]

然后:

U8*   pBuffers[((FAST)>(SLOW)?(FAST):(SLOW))]

然后终于:

U8*   pBuffers[((16)>(6)?(16):(6))]

实际上,预处理器不是很聪明,并且不会走得更远。

代码生成阶段,您的行将被解释为:

U8*   pBuffers[16]

因为代码生成器非常聪明。

答案 1 :(得分:1)

The C standard要求使用整数常量表达式声明大多数数组的大小,在编译时可以(在这种情况下)必须对其进行充分评估。 (唯一的例外是“可变长度数组”,并且它们必须是具有“自动存储持续时间”的函数局部变量,而不是静态分配的。)

因此,对您的问题的一个答案是您不必为此担心。如果你写

WHATEVER_TYPE variable[SOME EXPRESSION];

在文件范围内,SOME EXPRESSION在编译时将被评估为常量,否则编译将失败并且您将得到一个错误。

但是更有用的答案是解释在阅读代码时如何亲自查看SOME EXPRESSION是否为整数常量表达式。首先,您必须在脑子上扩展所有宏。然后,您大概会有某种算术表达式(如果不是,那是语法错误)。

此算术表达式是 constant 表达式,如果它没有副作用,不进行任何函数调用并且不引用任何变量的值(即使它不是constenum常数就可以了,就像字符串文字一样,只要sizeof variable被完全声明并且不是可变长度数组,就可以使用variable) 。此外,如果它不尝试执行任何浮点或指针算术(您可以将浮点文字作为强制类型转换的直接操作数),则它是一个 integer 常量表达式。 ,但是;例如((int)3.1415926)是一个整数常量表达式)。

所以,以你的例子为例,

#define MAX(a,b) ((a)>(b)?(a):(b))
#define FAST            16
#define SLOW            6
#define MAX_NUM         MAX(FAST,SLOW)
U8*   pBuffers[MAX_NUM];

宏扩展后,我们有了

U8* pBuffers[((16)>(6)?(16):(6))];

方括号内的表达式没有副作用,不进行任何函数调用,不引用任何变量的值,并且不执行任何浮点或指针算术,因此它是整数常量表达式,并且要求编译器在编译时对其进行求值。

相反,如果您使用的是MAX的定义,则:

static inline size_t MAX(size_t a, size_t b)
{ return a > b ? a : b; }

然后将产生宏扩展

U8* pBuffers[MAX(16, 8)];

并且方括号内的表达式将进行函数调用,因此它不是整数常量表达式,甚至不是常量表达式,而且会出现编译时错误。

(仅供参考,C ++中的规则要复杂得多;如果您需要了解这一点,请提出一个新问题。)

答案 2 :(得分:0)

总是在编译过程开始之前评估MACROS。因此,此代码无需担心,它应该可以正常工作。

同时,这整个过程取决于编译器,我相信使用gcc可以正常工作。也许,对于某些裸机应用,它可能会发出警告。