将签名解释为未签名

bbg*_*bbg 25 c++

我有这样的价值:

int64_t s_val = SOME_SIGNED_VALUE;
Run Code Online (Sandbox Code Playgroud)

我怎么能得到一个

uint64_t u_val
Run Code Online (Sandbox Code Playgroud)

具有完全相同的位模式s_val,但被视为无符号?

这可能非常简单,但在查看Stackoverflow和其他地方后,我没有找到答案.

Kir*_*sky 34

int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
Run Code Online (Sandbox Code Playgroud)

C++标准4.7/2指出:

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2 n,其中n是用于表示无符号类型的位数).[注意:在二进制补码表示中,此转换是概念性的,并且位模式没有变化(如果没有截断).]

另一方面,标准说"由reinterpret_cast执行定义执行的映射.[注意:它可能会或可能不会产生与原始值不同的表示."(5.2.10/3).所以,我建议使用static_cast.


Mic*_*urr 9

请注意,您根本不需要演员表.对于所有关于演员阵容是否会因为负面表现而变得无聊的争论,有一件事已经丢失 - 演员阵容完全没必要.

由于C/C++将进行转换(以及如何定义转换),因此:

int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = s_val;
Run Code Online (Sandbox Code Playgroud)

完全等同于:

int64_t s_val = SOME_SIGNED_VALUE;
uint64_t u_val = static_cast<uint64_t>(s_val);
Run Code Online (Sandbox Code Playgroud)

也就是说,你可能仍然想要演员,因为它表明意图.但是,我听说它认为你不应该使用不必要的强制转换,因为它可能会在你可能需要警告的情况下使编译器静音.

选择你的毒药.


int*_*nt3 7

一般来说,无论你是否使用static_cast<int64_t>或无关紧要reinterpret_cast<int64_t>.只要您在使用二进制补码表示负数的处理器上运行,结果就是相同的.(几乎所有现代处理器都使用它.)在二进制补码下,有符号整数中的正数在无符号整数中以相同的方式表示; 如果它是负数,它将被重新解释为无符号形式的大正数.

基本上,你的演员所做的是告诉编译器在处理该值时产生不同的汇编指令.例如,对于有符号整数的乘法和除法有不同的指令.虽然加法和减法保持不变(阅读维基百科链接,你会明白).


Rav*_*ven 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
Run Code Online (Sandbox Code Playgroud)

从小符号值转换为大的无符号值时,请注意符号扩展.可能其他组合也很脆弱 - 我没有想到它一直都是如此.

  • 请注意,第二行也允许生成“255”,因为允许实现使“char”无符号。 (2认同)

sse*_*ell 6

想要分享这个 C++14 现代通用解决方案。原来是在这里演示的。

template<class T> 
auto as_unsigned(T t) 
{ 
    return std::make_unsigned_t<T>(t); 
}
Run Code Online (Sandbox Code Playgroud)

可以按如下方式使用:

auto sx = int32_t{ 55 };
auto ux = as_unsigned(sx);
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看它的实际效果。


AnT*_*AnT 5

逻辑位模式(值表示的位),即二进制数字的值只有在原始有符号值为非负数时才能保留,因为负值不能用无符号整数变量表示.您需要做的就是将已签名的值分配给未签名的整数对象,然后就完成了

uint64_t u_val = s_val;
Run Code Online (Sandbox Code Playgroud)

显式强制转换不是必需的,但可能用于抑制编译器警告.

至于物理位模式(即你在原始内存中看到的,对象表示的位),你根本无法以这种方式"转换"它.C++语言没有为您提供任何可以保证保留物理位模式的转换方法.您所能做的就是将签名对象占用的内存重新解释为相同大小的无符号对象

STATIC_ASSERT(sizeof(int64_t) == sizeof(uint64_t));
uint64_t u_val = reinterpret_cast<uint64_t&>(s_val);
Run Code Online (Sandbox Code Playgroud)

同样,这不是转换,而是内存重新解释.这不能保证工作,这通常是非法的.