我什么时候应该在C中使用UINT32_C(),INT32_C(),...宏?

Tim*_*gan 20 c misra fixed-width uint32-t

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

要为固定长度变量分配常量值,我可以使用像UINT32_C()和的宏INT32_C().每当我分配一个恒定值时,我就开始使用它们.

这导致代码类似于:

uint64_t i;
for (i = UINT64_C(0); i < UINT64_C(10); i++) { ... }
Run Code Online (Sandbox Code Playgroud)

现在我看到几个不关心它的例子.一个是stdbool.h包含文件:

#define bool    _Bool
#define false   0
#define true    1
Run Code Online (Sandbox Code Playgroud)

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

uint64_t i;
for (i = 0; i < 10; i++) { ... }
Run Code Online (Sandbox Code Playgroud)

那么我何时应该使用固定长度的常量宏UINT32_C(),何时应该将该工作留给编译器(我正在使用GCC)?如果我在MISRA C中编写代码怎么办?

Lun*_*din 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 有一整套关于这个概念的规则,本质上称为布尔类型。这可以在静态分析期间提供更好的类型安全性,也可以防止各种错误。