我在某人的 C 源代码中偶然发现了以下内容:
typedef struct {
u32 reg;
} reg_t;
#define _REG(r) ((const reg_t){.reg=(r)})
#define REG_A _REG(123)
#define REG_B _REG(456)
...
这让我想知道:这种巫术的目的是什么?难道不能只定义一个简单的数值常量吗?为什么他们定义一个结构体,只有一个成员,然后使用 C99 的复合文字来初始化它?我在这里缺少一些需要这样的语法的晦涩的好处吗?
(一开始我也对这个语法感到困惑,直到我发现它是一个 C99 扩展。我知道“指定初始化器”,但我不知道它们可以这样使用,看起来像就像类型转换,但据我了解,这只是 C99 做类似于 C++ 构造函数的方式。不过,我不知道他们为什么在这里特别使用这个技巧,以及如果他们不这样做会发生什么。 )
这种巫术的目的可能是什么?
目的是让
_REG
具有类型const reg_t
。
难道不能只定义一个简单的数值常数吗?
一切皆有可能。最有可能的是,您可以重写代码。
为什么他们定义一个结构体,只有一个成员,然后使用 C99 的复合文字来初始化它?
使
_REG
的类型为const reg_t
。用于类型检查。
它是 C99 扩展
C语言中的“扩展”,是标准之外的额外部分。特定的编译器有特定的“扩展”,它“扩展”了基本语言。就像 GCC 编译器有
__attribute__()
函数属性语法,其他编译器没有。
复合文字不是多余的。它们是内部的,符合 C99 标准。所有 C99 编译器都有复合文字。
简单类型检查示例:
uint8_t reg_get(const reg_t ret);
int main() {
reg_get(REG_A); // OK
reg_get(123); // error
}
注意:根据所示代码,它们没有理由是
#define
。我会做static const reg_t REG_A = {123};
。除非它们用于#ifdef
。
注意:以下划线和大写字母开头的标识符在 C99 中被保留。使用代码不允许使用它们。
注意:更喜欢使用
uint32_t
中的标准 stdint.h
而不是用户定义的类型。