用于定义常量的奇怪宏

问题描述 投票:0回答:1

我在某人的 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++ 构造函数的方式。不过,我不知道他们为什么在这里特别使用这个技巧,以及如果他们不这样做会发生什么。 )

macros c-preprocessor c99 compound-literals
1个回答
0
投票

这种巫术的目的可能是什么?

目的是让

_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
而不是用户定义的类型。

© www.soinside.com 2019 - 2024. All rights reserved.