C 宏观评价
C MACRO evaluation
我想声明一个静态分配的数组。
我们来看看下面的代码:
#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 是常量并且作为编译的一部分或由预处理器进行评估。
MACROS 总是在编译过程开始之前进行评估。所以这段代码没有什么可担心的,它应该可以正常工作。
同时,这一切都依赖于编译器,我相信 gcc
它会工作得很好。也许,对于某些裸机应用程序,它可能会发出警告。
启动编译器时,将(顺序)执行以下阶段:
- 预处理:它管理#define、#ifdef / #endif...
- 代码生成:它生成可在目标上运行的机器代码CPU
- 优化:根据用户选项进行优化
在预处理阶段,预处理器将例如"replace"你的行:
U8* pBuffers[MAX(FAST,SLOW)]
然后:
U8* pBuffers[((FAST)>(SLOW)?(FAST):(SLOW))]
然后最后:
U8* pBuffers[((16)>(6)?(16):(6))]
确实预处理器不是很聪明,没有更进一步
在代码生成阶段,您的行将被解释为:
U8* pBuffers[16]
因为代码生成器非常聪明。
The C standard 要求使用 整数常量表达式 来声明大多数数组的大小,这可以并且在这种情况下需要被完全计算在编译时。 (唯一的例外是 "variable length arrays",它们必须是带有 "automatic storage duration" 的函数局部变量——不是静态分配的。)
因此,您的问题的一个答案是您不必担心。如果你写
WHATEVER_TYPE variable[SOME EXPRESSION];
在文件范围内,SOME EXPRESSION
将在编译时被评估为常量,否则编译将失败,您将得到一个错误。
但更有用的答案是解释如何在阅读代码时自己查看 SOME EXPRESSION
是否是整数常量表达式。首先,你必须在心里展开所有的宏。然后,您可能会有某种算术表达式(如果没有,则为语法错误)。
这个算术表达式是一个常量表达式,如果它没有副作用,不进行任何函数调用,并且不引用任何变量的值(即使它是 const
) (enum
常量也可以,字符串文字也是如此,并且 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++ 中的规则要复杂得多;如果您需要了解这一点,请提出一个新问题。)
我想声明一个静态分配的数组。 我们来看看下面的代码:
#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 是常量并且作为编译的一部分或由预处理器进行评估。
MACROS 总是在编译过程开始之前进行评估。所以这段代码没有什么可担心的,它应该可以正常工作。
同时,这一切都依赖于编译器,我相信 gcc
它会工作得很好。也许,对于某些裸机应用程序,它可能会发出警告。
启动编译器时,将(顺序)执行以下阶段:
- 预处理:它管理#define、#ifdef / #endif...
- 代码生成:它生成可在目标上运行的机器代码CPU
- 优化:根据用户选项进行优化
在预处理阶段,预处理器将例如"replace"你的行:
U8* pBuffers[MAX(FAST,SLOW)]
然后:
U8* pBuffers[((FAST)>(SLOW)?(FAST):(SLOW))]
然后最后:
U8* pBuffers[((16)>(6)?(16):(6))]
确实预处理器不是很聪明,没有更进一步
在代码生成阶段,您的行将被解释为:
U8* pBuffers[16]
因为代码生成器非常聪明。
The C standard 要求使用 整数常量表达式 来声明大多数数组的大小,这可以并且在这种情况下需要被完全计算在编译时。 (唯一的例外是 "variable length arrays",它们必须是带有 "automatic storage duration" 的函数局部变量——不是静态分配的。)
因此,您的问题的一个答案是您不必担心。如果你写
WHATEVER_TYPE variable[SOME EXPRESSION];
在文件范围内,SOME EXPRESSION
将在编译时被评估为常量,否则编译将失败,您将得到一个错误。
但更有用的答案是解释如何在阅读代码时自己查看 SOME EXPRESSION
是否是整数常量表达式。首先,你必须在心里展开所有的宏。然后,您可能会有某种算术表达式(如果没有,则为语法错误)。
这个算术表达式是一个常量表达式,如果它没有副作用,不进行任何函数调用,并且不引用任何变量的值(即使它是 const
) (enum
常量也可以,字符串文字也是如此,并且 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++ 中的规则要复杂得多;如果您需要了解这一点,请提出一个新问题。)