我有一个问题。
uint64_t var = 1; // this is 000000...00001 right?
在我的代码中,这个可以工作:
var ^ (1 << 43)
但是它如何知道1应该在64位中呢?我不应该写成这样吗?
var ^ ( (uint64_t) 1 << 43 )
正如您所想,1是普通的带符号int
(在您的平台上可能是32位宽度的2的补码算术),43也是如此,因此如果偶然出现1<<43
,结果会导致溢出:事实上,如果两个参数都是int
类型,则运算符规则指定结果也将是一个int
。
然而,在C中,带符号整型溢出是未定义行为,因此原则上任何事情都可能发生。在您的情况下,编译器可能会发出代码,在64位寄存器中执行该移位操作,所以通过幸运,它似乎可以工作;为了获得保证正确的结果,您应该使用您写的第二种形式,或者,作为替代方案,使用ull
后缀将1
指定为unsigned long long
字面量(unsigned long long
至少保证为64位)。
var ^ ( 1ULL << 43 )
我推荐 OP 的方法,将常量 ( (uint64_t) 1 << 43 )
转换。
对于 OP 的小例子,下面的两种方法很可能表现相同。
uint64_t var = 1;
// OP solution)
var ^ ( (uint64_t) 1 << 43 )
// Others suggested answer
var ^ ( 1ULL << 43 )
以上结果具有相同的值,但不同的类型。这两种类型在C语言中的存在可能导致潜在差异:uint64_t
和unsigned long long
以及后续可能发生的情况。
uint64_t
具有确切的范围0到264-1。
unsigned long long
的范围为0至至少264-1。
如果unsigned long long
始终是64位,就像许多现代计算机那样,那么就没有问题了。但是,让我们展望未来,假设这段代码在一个unsigned long long
为16字节(0到至少2128-1)的机器上运行。
下面是一个人为制造的例子:第一个^
的结果是一个uint64_t
,当乘以3时,积仍将是一个uint64_t
,执行模264,如果溢出可能发生,则将结果分配给d1
。在下一个情况中,^
的结果是一个unsigned long long
,当乘以3时,积可能大于264,然后将其分配给d2
。因此,d1
和d2
具有不同的答案。
double d1, d2;
d1 = 3*(var ^ ( (uint64_t) 1 << 43 ));
d2 = 3*(var ^ ( 1ULL << 43 ));
如果想要使用 unit64_t
进行工作,请保持一致性。不要假设 unit64_t
和 unsigned long long
是相同的。如果你的答案可以是 unsigned long long
,那就没问题了。但我的经验告诉我,如果开始使用像 uint64_t
这样的固定大小类型,那么就不想让变长类型捣乱影响计算结果。一个便携式的获得 unit64_t
常量的方法是使用 stdint.h
中的 UINT64_C
宏:
UINT64_C(1) << 43
很可能UINT64_C(c)
被定义为类似于c##ULL
的东西。
从C标准来看:
宏
INTN_C(value)
应扩展为与类型int_least
N_t
相对应的整数常量表达式。宏UINTN_
C(value)
应扩展为与类型uint_least
N_t
相对应的整数常量表达式。例如,如果uint_least64_t
是unsigned long long int
类型的名称,则UINT64_C(0x123)
可能会扩展为整数常量0x123ULL
。
var ^ ( 1ULL << 43 )
should do it.
float x = 1/2
导致 x
包含0而不是0.5 的问题相同:只有操作数的类型才能确定算术运算符的行为。任何一个 (uint64)1 << 43
或 (long long)1 << 43
或 (unsigned long long)1 << 43
或 1ll << 43
或 1ull << 43
都可以。如果使用有符号类型,则仅在没有溢出时定义行为,因此如果您期望截断溢出,请务必使用无符号类型。即使不应该发生溢出,通常也建议使用无符号类型,因为行为是可重现的——如果使用有符号类型,则仅打印调试目的的值就可能改变行为(因为编译器喜欢利用未定义的行为生成在微观层面上最有效的代码,这可能非常敏感,例如寄存器分配压力)。uint64_t
类型,因此最好使用该类型执行所有计算。因此:uint64_t var = 1;
… var ^ ((uint64_t)1 << 43) …
0x12345
是一个 有符号的
整数而不是一个 无符号的
整数。 - chux - Reinstate Monica
1<<43
会自动提升为long long
。 - ratchet freak