21

我在我的项目中切换到固定长度的整数类型主要是因为它们帮助我在使用它们时更清楚地考虑整数大小。包括它们 via#include <inttypes.h>还包括一堆其他宏,例如打印宏PRIu32,,PRIu64...

要将常量值分配给固定长度的变量,我可以使用 和 之类的UINT32_C()INT32_C()。每当我分配一个常数值时,我就开始使用它们。

这导致类似于以下的代码:

uint64_t i;
for (i = UINT64_C(0); i < UINT64_C(10); i++) { ... }

现在我看到了几个不关心这一点的例子。一种是stdbool.h包含文件:

#define bool    _Bool
#define false   0
#define true    1

bool我的机器上有 1 个字节的大小,所以它看起来不像int. 但是0and1应该是整数,应该由编译器自动转换为正确的类型。如果我在我的示例中使用它,代码会更容易阅读:

uint64_t i;
for (i = 0; i < 10; i++) { ... }

那么我什么时候应该使用固定长度的常量宏UINT32_C(),什么时候应该把这项工作留给编译器(我使用的是 GCC)?如果我用 MISRA C 编写代码会怎样?

4

2 回答 2

5

根据经验,当文字的类型很重要时,您应该使用它们。有两件事需要考虑:大小和签名。

关于尺寸:

一个int类型由 C 标准值保证,最高可达32767. 由于您无法获得类型小于 的整数文字,因此小于的int所有值32767都不需要使用宏。如果您需要更大的值,那么文字的类型开始很重要,使用这些宏是个好主意。

关于签名:

没有后缀的整数文字通常是有符号类型。这是潜在的危险,因为它可能在隐式类型提升期间导致各种微妙的错误。例如(my_uint8_t + 1) << 31,在 32 位系统上会导致未定义的行为错误,而(my_uint8_t + 1u) << 31不会。

这就是为什么 MISRA 有一条规则指出,如果打算使用无符号类型,所有整数文字都应该有一个u/后缀。U所以在我上面的例子中,你可以使用my_uint8_t + UINT32_C(1),但你也可以使用1u,这可能是最易读的。对于 MISRA 来说,两者都应该没问题。


至于为什么 stdbool.h 将 true/false 定义为 1/0,是因为标准明确说明了这一点。出于向后兼容的原因, C 中的布尔条件仍然使用int类型,而不是bool像 C++ 中的类型。

然而,将布尔条件视为 C 具有真正的布尔类型被认为是一种很好的风格。MISRA-C:2012 对此概念有一整套规则,本质上称为布尔类型。这可以在静态分析期间提供更好的类型安全性,还可以防止各种错误。

于 2016-11-28T10:41:37.873 回答
3

它用于使用较小的整数文字,其中上下文不会导致编译器将其转换为正确的大小。

我在一个int16 位和long32 位的嵌入式平台上工作过。如果您尝试编写可移植代码以在具有 16 位或 32 位int类型的平台上工作,并希望将 32 位“无符号整数文字”传递给可变参数函数,则需要强制转换:

#define BAUDRATE UINT32_C(38400)
printf("Set baudrate to %" PRIu32 "\n", BAUDRATE);

在 16 位平台上,演员创建38400UL和在 32 位平台上只是38400U. 这些将匹配or的PRIu32宏。"lu""u"

我认为大多数编译器会生成与何时是整数文字相同的代码,但早期编译器可能并非如此(uint32_t) XUINT32_C(X)X

于 2016-11-28T02:07:58.583 回答