我有一个像这样的值:
int64_t s_val = SOME_SIGNED_VALUE;
我该怎么获取
uint64_t u_val
如何得到一个无符号整数,它与s_val
具有相同的二进制模式,但被视为无符号数?
这可能非常简单,但是在 Stackoverflow 和其他地方搜索之后,我没有找到答案。
我有一个像这样的值:
int64_t s_val = SOME_SIGNED_VALUE;
我该怎么获取
uint64_t u_val
如何得到一个无符号整数,它与s_val
具有相同的二进制模式,但被视为无符号数?
这可能非常简单,但是在 Stackoverflow 和其他地方搜索之后,我没有找到答案。
int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
C++标准4.7/2规定:
如果目标类型是无符号的,则结果值为源整数模2n的最小无符号整数余数,其中n是用于表示无符号类型的位数。 [注意:在二进制补码表示中,此转换是概念性的,如果没有截断,则不会更改位模式。 ]
另一方面,标准规定“由reinterpret_cast
执行的映射是实现定义的。[注意:它可能会产生与原始值不同的表示,也可能不会。]”(5.2.10/3)。因此,我建议使用static_cast
。
请注意,你根本不需要进行强制转换。尽管人们一直争论强制转换是否会对负数表示混淆位,但有一点已经被忽略了——强制转换是完全不必要的。
由于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);
话虽如此,您可能仍然希望进行强制类型转换,因为它表明了意图。 然而,有人认为您不应该使用不必要的强制类型转换,因为它会在某些情况下使编译器保持沉默,而您可能想要一个警告。
选择你的毒药。
我同意在这种情况下使用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
在将小的有符号值转换为大的无符号值时,要注意符号扩展。可能还有其他组合也存在漏洞——我还没有完全考虑清楚。
255
,因为实现允许使 char
无符号。 - mtraceur一般来说,使用static_cast<int64_t>
或reinterpret_cast<int64_t>
都无所谓。只要您在运行使用二进制补码表示负数的处理器上,结果是相同的。(现代几乎所有处理器都使用这种方式)。在二进制补码下,有符号整数中的正数和无符号整数中的正数表示方式相同;如果是负数,则会在无符号形式下重新解释为一个大的正数。
基本上,您的类型转换让编译器在处理该值时生成不同的汇编指令。例如,对于有符号整数,乘法和除法有不同的指令。尽管加法和减法保持不变(阅读维基百科链接,您将理解)。
逻辑位模式(即值表示的比特位),即二进制数字的值只有在原始有符号值为非负数时才能被保留,因为负值不能由无符号整数变量表示。您只需要将有符号值分配给无符号整数对象即可完成此操作。
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);
需要说明的是,这不是一种转换,而是一种内存重新解释。这种方法不能保证可行,通常是非法的。
T
的对象占用的内存作为不同类型U
的对象进行访问(有少数例外)。换句话说,重新解释内存的读取几乎总是非法的。 - AnT stands with Russia您还可以使用reinterpret_cast
或使用union
:
union {
int64_t i64;
uint64_t ui64;
} variable;
variable.i64 = SOME_SIGNED_VALUE;
uint64_t a_copy = variable.ui64;
static_cast
不会导致位模式丢失。 - Kirill V. Lyadvinskystatic_cast
使用来自4.7/2的转换。 - Kirill V. Lyadvinsky