什么时候应该在C中使用UINT32_C(),INT32_C(),...宏? [英] When should I use UINT32_C(), INT32_C(),... macros in C?
问题描述
我在项目中切换到定长整数类型的主要原因是,它们在使用它们时帮助我更清楚地考虑整数大小.通过#include <inttypes.h>
包括它们还包括许多其他宏,例如打印宏PRIu32
,PRIu64
,...
I switched to fixed-length integer types in my projects mainly because they help me think about integer sizes more clearly when using them. Including them via #include <inttypes.h>
also includes a bunch of other macros like the printing macros PRIu32
, PRIu64
,...
要将常量值分配给固定长度的变量,我可以使用UINT32_C()
和INT32_C()
之类的宏.每当我分配一个恒定值时,我就开始使用它们.
To assign a constant value to a fixed length variable I can use macros like UINT32_C()
and INT32_C()
. I started using them whenever I assigned a constant value.
这导致类似于以下代码:
This leads to code similar to this:
uint64_t i;
for (i = UINT64_C(0); i < UINT64_C(10); i++) { ... }
现在我看到了几个无关紧要的例子.一个是stdbool.h
包含文件:
Now I saw several examples which did not care about that. One is the stdbool.h
include file:
#define bool _Bool
#define false 0
#define true 1
bool
在我的机器上的大小为1个字节,因此它看起来不像int
.但是0
和1
应该是整数,编译器应将其自动转换为正确的类型.如果我在示例中使用该代码,则代码将更容易阅读:
bool
has a size of 1 byte on my machine, so it does not look like an int
. But 0
and 1
should be integers which should be turned automatically into the right type by the compiler. If I would use that in my example the code would be much easier to read:
uint64_t i;
for (i = 0; i < 10; i++) { ... }
那么我什么时候应该使用像UINT32_C()
这样的固定长度常量宏,什么时候应该将其工作留给编译器(我正在使用GCC)?如果我要用MISRA C编写代码怎么办?
So when should I use the fixed length constant macros like UINT32_C()
and when should I leave that work to the compiler(I'm using GCC)? What if I would write code in MISRA C?
推荐答案
作为经验法则,当文字类型很重要时,应使用它们.有两件事要考虑:大小和签名.
As a rule of thumb, you should use them when the type of the literal matters. There are two things to consider: the size and the signedness.
关于尺寸:
int
类型由最高32767
的C标准值保证.由于无法获得类型小于int
的整数文字,因此所有小于32767
的值都不需要使用宏.如果需要更大的值,那么文字的类型就开始重要了,最好使用这些宏.
An int
type is guaranteed by the C standard values up to 32767
. Since you can't get an integer literal with a smaller type than int
, all values smaller than 32767
should not need to use the macros. If you need larger values, then the type of the literal starts to matter and it is a good idea to use those macros.
关于签名:
不带后缀的整数文字通常是带符号的类型.这是潜在的危险,因为它可能在隐式类型提升期间导致各种形式的细微错误.例如,(my_uint8_t + 1) << 31
会在32位系统上导致未定义的行为错误,而(my_uint8_t + 1u) << 31
不会.
Integer literals with no suffix are usually of a signed type. This is potentially dangerous, as it can cause all manner of subtle bugs during implicit type promotion. For example (my_uint8_t + 1) << 31
would cause an undefined behavior bug on a 32 bit system, while (my_uint8_t + 1u) << 31
would not.
这就是为什么MISRA有一条规则规定,如果要使用无符号类型,则所有整数文字都应带有u
/U
后缀.因此,在上面的示例中,您可以使用my_uint8_t + UINT32_C(1)
,但也可以使用1u
,这也许是最易读的.对于MISRA来说都可以.
This is why MISRA has a rule stating that all integer literals should have an u
/U
suffix if the intention is to use unsigned types. So in my example above you could use my_uint8_t + UINT32_C(1)
but you can as well use 1u
, which is perhaps the most readable. Either should be fine for MISRA.
至于为什么stdbool.h将true/false定义为1/0,这是因为标准明确指出了这一点.由于向后兼容的原因,C中的布尔条件仍然使用int
类型,而不是像C ++中那样使用bool
类型.
As for why stdbool.h defines true/false to be 1/0, it is because the standard explicitly says so. Boolean conditions in C still use int
type, and not bool
type like in C++, for backwards compatibility reasons.
但是,将布尔条件视为C具有真正的布尔类型被认为是一种好的样式. MISRA-C:2012具有与此概念有关的一整套规则,称为本质上是布尔类型.这样可以在静态分析期间提供更好的类型安全性,并防止各种错误.
It is however considered good style to treat boolean conditions as if C had a true boolean type. MISRA-C:2012 has a whole set of rules regarding this concept, called essentially boolean type. This can give better type safety during static analysis and also prevent various bugs.
这篇关于什么时候应该在C中使用UINT32_C(),INT32_C(),...宏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!