简体   繁体   English

uint64_t的安全低32位屏蔽

[英]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表示,因此它的类型将是intunsigned intlong intunsigned 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM