繁体   English   中英

uint64_t的安全低32位屏蔽

[英]Safe low 32 bits masking of uint64_t

假设以下代码:

uint64_t g_global_var;

....
....

void foo(void)
{
    uint64_t local_32bit_low = g_global_var & 0xFFFFFFFF;
    ....
}

在当前的工具链,这个代码正常工作, local_32bit_low确实含有的低32位g_global_var

我想知道标准C是否保证此代码始终按预期工作? 我担心的是编译器可能将0xFFFFFFFF视为-1的整数值,当提升到uint64_t ,它将变为0xFFFFFFFFFFFFFFFF。

PS

我知道为了安全起见,在这种情况下最好使用0xFFFFFFFFULL。 关键是我在遗留代码中看到它,我想知道它是否值得修复。

没有问题。 整数常量0xFFFFFFFF具有能够按原样存储值的类型。

根据C标准(6.4.4.1整数常数)

5整数常量的类型是相应列表中可以表示其值的第一个

因此,此值存储为正值。

如果unsigned int类型是32位整数类型,则常量将具有unsigned int类型。

否则它将具有可以存储值的类型之一。

long int
unsigned long int
long long int
unsigned long long int 

由于表达式中通常的算术转换

g_global_var & 0xFFFFFFFF;

它被提升为

0x00000000FFFFFFFF

注意在C中没有负整数常量。 例如,表达式

-10

由两个子表达式组成:主表达式10和带有一元运算符的子表达式- -19与完整表达式一致。

0xffffffff不是-1,永远。 如果你强制转换(或通过赋值)它可以转换为-1,它可以转换为有符号的32位类型,但C中的整数文字总是有它们的数学值,除非它们溢出。

对于十进制文字,类型是可以表示值的最窄签名类型。 对于十六进制文字,在进入下一个更宽的签名类型之前使用无符号类型。 因此,在int为32位的常见情况下,0xffffffff将具有unsigned int类型。 如果你把它写成十进制,它将有long类型(如果long是64位)或long long (如果long只有32位)。

未填充的十六进制或八进制常量的类型是以下列表中的第一个,其值可以表示为:

int
unsigned int
long int
unsigned long int
long long int
unsigned long long int

(对于未加十进制的十进制常量,请从上面的列表中删除unsigned类型。)

十六进制常量0xFFFFFFFF绝对可以用unsigned long int表示,因此它的类型将是intunsigned intlong intunsigned long int ,可以表示其值。

请注意,虽然0xFFFFFFFF > 0总是计算为1(真),但在不同的实现上, 0xFFFFFFFF > -1可能会计算为0(假)或1(真)。 因此,在将整数常量相互比较或与整数类型的其他对象进行比较时需要注意。

其他人已经回答了这个问题,只是一个推荐,下次(如果你在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;
}

输出是

uint64_t

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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