[英]Safe low 32 bits masking of uint64_t
Assume the following code: 假设以下代码:
uint64_t g_global_var;
....
....
void foo(void)
{
uint64_t local_32bit_low = g_global_var & 0xFFFFFFFF;
....
}
With the current toolchain, this code works as expected, local_32bit_low
indeed contains the low 32 bits of g_global_var
. 在当前的工具链,这个代码正常工作,
local_32bit_low
确实含有的低32位g_global_var
。
I wonder if it is guaranteed by the standard C that this code will always work as expected? 我想知道标准C是否保证此代码始终按预期工作? My concern is that the compiler may treat 0xFFFFFFFF as integer value of -1 and when promoting to
uint64_t
it would become 0xFFFFFFFFFFFFFFFF. 我担心的是编译器可能将0xFFFFFFFF视为-1的整数值,当提升到
uint64_t
,它将变为0xFFFFFFFFFFFFFFFF。
PS PS
I know that to be on the safe side it is better to use 0xFFFFFFFFULL in this case. 我知道为了安全起见,在这种情况下最好使用0xFFFFFFFFULL。 The point is that I saw it in a legacy code and I wonder if it worth to be fixed or not.
关键是我在遗留代码中看到它,我想知道它是否值得修复。
There is no problem. 没有问题。 The integer constant
0xFFFFFFFF
has the type that is able to store the value as is. 整数常量
0xFFFFFFFF
具有能够按原样存储值的类型。
According to the C Standard (6.4.4.1 Integer constants) 根据C标准(6.4.4.1整数常数)
5 The type of an integer constant is the first of the corresponding list in which its value can be represented
5整数常量的类型是相应列表中可以表示其值的第一个
So this value is stored as a positive value. 因此,此值存储为正值。
If the type unsigned int
is a 32-bit integer type then the constant will have the type unsigned int
. 如果
unsigned int
类型是32位整数类型,则常量将具有unsigned int
类型。
Otherwise it will have one of the types that can store the value. 否则它将具有可以存储值的类型之一。
long int
unsigned long int
long long int
unsigned long long int
Due to the usual arithmetic conversions in the expression 由于表达式中通常的算术转换
g_global_var & 0xFFFFFFFF;
it is promoted like 它被提升为
0x00000000FFFFFFFF
Pay attention to that in C there is no negative integer constants. 注意在C中没有负整数常量。 For example an expression like
例如,表达式
-10
consists of two sub-expressions: the primary expression 10
and the sub-expression with the unary operator -
-19
that coincides with the full expression. 由两个子表达式组成:主表达式
10
和带有一元运算符的子表达式-
-19
与完整表达式一致。
0xffffffff is not -1, ever. 0xffffffff不是-1,永远。 It may convert to -1 if you cast or coerce (eg by assignment) it to a signed 32-bit type, but integer literals in C always have their mathematical value unless they overflow.
如果你强制转换(或通过赋值)它可以转换为-1,它可以转换为有符号的32位类型,但C中的整数文字总是有它们的数学值,除非它们溢出。
For decimal literals, the type is the narrowest signed type that can represent the value. 对于十进制文字,类型是可以表示值的最窄签名类型。 For hex literals, unsigned types are used before going up to the next wider signed type.
对于十六进制文字,在进入下一个更宽的签名类型之前使用无符号类型。 So, in the common case where
int
is 32-bit, 0xffffffff would have type unsigned int
. 因此,在
int
为32位的常见情况下,0xffffffff将具有unsigned int
类型。 If you wrote it as decimal, it would have type long
(if long
is 64-bit) or long long
(if long
is only 32-bit). 如果你把它写成十进制,它将有
long
类型(如果long
是64位)或long long
(如果long
只有32位)。
The type of an unsuffixed hexadecimal or octal constant is the first of the following list in which its value can be represented: 未填充的十六进制或八进制常量的类型是以下列表中的第一个,其值可以表示为:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
(For unsuffixed decimal constants, remove the unsigned
types from the above list.) (对于未加十进制的十进制常量,请从上面的列表中删除
unsigned
类型。)
The hexadecimal constant 0xFFFFFFFF
can definitely be represented by unsigned long int
, so its type will be the first of int
, unsigned int
, long int
or unsigned long int
that can represent its value. 十六进制常量
0xFFFFFFFF
绝对可以用unsigned long int
表示,因此它的类型将是int
, unsigned int
, long int
或unsigned long int
,可以表示其值。
Note that although 0xFFFFFFFF > 0
always evaluates to 1 (true), it is possible for 0xFFFFFFFF > -1
to evaluate to either 0 (false) or 1 (true) on different implementations. 请注意,虽然
0xFFFFFFFF > 0
总是计算为1(真),但在不同的实现上, 0xFFFFFFFF > -1
可能会计算为0(假)或1(真)。 So you need to be careful when comparing integer constants with each other or with other objects of integer type. 因此,在将整数常量相互比较或与整数类型的其他对象进行比较时需要注意。
Others have answered the question, just a recomendation, next time (if you are under C11) you can check the type of the expression by yourself using _Generic
其他人已经回答了这个问题,只是一个推荐,下次(如果你在C11下)你可以自己使用
_Generic
检查表达式的类型
#include <stdio.h>
#include <stdint.h>
#define print_type(x) _Generic((x), \
int64_t: puts("int64_t"), \
uint64_t: puts("uint64_t"), \
default: puts("unknown") \
)
uint64_t g_global_var;
int main(void)
{
print_type(g_global_var & 0xFFFFFFFF);
return 0;
}
The ouput is 输出是
uint64_t
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.