我有这样的价值:
int64_t s_val = SOME_SIGNED_VALUE;
我怎样才能获得
uint64_t u_val
与s_val
具有完全相同的位模式,但被视为无符号?
这可能非常简单,但在查看Stackoverflow和其他地方之后,我还没有找到答案。
答案 0 :(得分:33)
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
C ++标准4.7 / 2声明:
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2 n ,其中n是用于表示无符号类型的位数)。 [注意:在二进制补码表示中,此转换是概念性的,并且位模式没有变化(如果没有截断)。 ]
另一方面,标准说“由reinterpret_cast
执行的映射是实现定义的。[注意:它可能会或可能不会产生与原始值不同的表示。]”(5.2。 10/3)。所以,我建议使用static_cast
。
答案 1 :(得分:9)
请注意,您根本不需要演员表。对于所有关于演员是否会因为否定表达而进行争吵的争论,有一件事已经丢失 - 演员阵容完全没必要。
由于C / C ++将进行转换(以及如何定义转换),因此:
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = s_val;
完全等同于:
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
那就是说,你可能仍然想要演员,因为它标志着意图。但是,我听说它认为你不应该使用不必要的强制转换,因为它可能会在你可能想要警告的情况下使编译器静音。
选择你的毒药。
答案 2 :(得分:7)
一般来说,使用static_cast<int64_t>
或reinterpret_cast<int64_t>
并不重要。只要您在使用two's complement表示负数的处理器上运行,结果就是相同的。 (实际上所有现代处理器都使用它。)在二进制补码下,有符号整数中的正数在无符号整数中以相同的方式表示;如果它是负数,它将被重新解释为无符号形式的大正数。
基本上,你的演员所做的是告诉编译器在处理该值时产生不同的汇编指令。例如。有符号整数的乘法和除法有不同的指令。虽然加法和减法保持不变(阅读维基百科链接,你会明白)。
答案 3 :(得分:6)
我同意static_cast在这种情况下是合适的,但是没有人提到过一个非常类似的情况,其中static_cast不会像预期的那样保留位。
char x = -1; // 255
unsigned int x2 = static_cast<unsigned int>(x); // 4294967295
unsigned int x3 = static_cast<unsigned int>(static_cast<unsigned char>(x)); // 255
当您从一个小的有符号值转换为一个大的无符号值时,请注意sign extension。可能其他组合也很脆弱 - 我没有想到它。
答案 4 :(得分:5)
逻辑位模式(值表示的位),即,如果原始有符号值是非负的,则只能保留二进制数字的值,因为负值不能由无符号整数变量表示。您需要做的就是将已签名的值分配给未签名的整数对象,然后就完成了
uint64_t u_val = s_val;
不需要显式强制转换,但可以用来抑制编译器警告。
对于物理位模式(即您在原始内存中看到的,对象表示的位),您根本无法以这种方式“转换”它。 C ++语言没有为您提供任何可以保证保留物理位模式的转换方法。您所能做的就是将签名对象占用的内存重新解释作为相同大小的无符号对象
STATIC_ASSERT(sizeof(int64_t) == sizeof(uint64_t));
uint64_t u_val = reinterpret_cast<uint64_t&>(s_val);
同样,这不是转换,而是内存重新解释。这不能保证工作,这通常是非法的。
答案 5 :(得分:2)
您也可以reinterpret_cast
,或使用union
:
union {
int64_t i64;
uint64_t ui64;
} variable;
variable.i64 = SOME_SIGNED_VALUE;
uint64_t a_copy = variable.ui64;
答案 6 :(得分:2)