C++ 将无符号解释为有符号

C++ 将无符号解释为有符号,c++,embedded,reinterpret-cast,static-cast,C++,Embedded,Reinterpret Cast,Static Cast,我在嵌入式平台(ARM)上工作,在处理位模式时必须小心。让我们假设这句话不受我的影响: uint8_t foo = 0xCE; // 0b11001110 解释为未签名,这将是206。但实际上它是有符号的,因此类似于-50。如何继续使用此值作为签名 int8_t bar = foo; // doesn't work 两者都没有(导致所有输入值为0x10或0x00) int8\u t bar=static\u cast(foo); int8_t bar=

我在嵌入式平台(ARM)上工作,在处理位模式时必须小心。让我们假设这句话不受我的影响:

uint8_t foo = 0xCE;          // 0b11001110
解释为未签名,这将是206。但实际上它是有符号的,因此类似于-50。如何继续使用此值作为签名

int8_t bar = foo;            // doesn't work
两者都没有(导致所有输入值为0x10或0x00)

int8\u t bar=static\u cast(foo);
int8_t bar=重新解释铸造(foo);
我只希望这些位保持不变,即。
(bar==0xCE)


反之亦然,我感兴趣的是如何将表示负数的位模式转换成无符号变量,而不会弄乱位模式。我正在使用GCC。

以下内容对我来说很好,正如评论所说,这是实现定义的:

int x = (signed char)(foo);
在C++中,你也可以说:

int x = static_cast<signed char>(foo);
intx=static\u cast(foo);
请注意,升级总是在重新解释位模式之前尝试保留值。因此,首先必须强制转换为与无符号类型大小相同的有符号类型,以强制重新解释有符号类型


(当我试图将
char
s打印为一对十六进制数字时,通常会遇到相反的问题。)

这方面有什么难看的地方吗

int8_t bar = (foo > 127) ? ((int)foo - 256) : foo;

不依赖于行为未定义的转换。

对于GCC,即使在嵌入式平台上,无符号值也可能是两个值的补充

然后8位数字
0xCE
表示
0xCE-256

因为二的补码实际上是模2n,其中n是表示中的位数

uint8_t foo = 0xCE;          
int8_t bar = *reinterpret_cast<int8_t*>(&foo);
编辑:嗯,为了代表的利益,我最好给出一个具体的例子:

int8_t toInt8( uint8_t x )
{
    return (x >= 128? x - 256 : x);
}
编辑2:我没有看到关于如何将位模式放入无符号变量的最后一个问题。这非常简单:只需分配。结果是由C++标准保证的,即存储的值是一致的(在时钟面上等于),赋给值,模2n。 干杯

uint8_t foo = 0xCE;          // 0b11001110
int8_t bar;
memcpy( &bar, &foo, 1 );

它甚至还有额外的好处,99%的编译器将完全优化对memcpy的调用…

您可以使用指针访问值的表示形式。通过重新解释指针类型而不是值类型,您应该能够复制表示

uint8_t foo = 0xCE;          
int8_t bar = *reinterpret_cast<int8_t*>(&foo);
uint8\u t foo=0xCE;
int8\u t bar=*重新解释演员阵容(&foo);

我想你的意思可能是256,而不是128,是吗?事实上,你可能是正确的,通常的算术转换意味着不需要强制转换(无论是C还是C++风格)。但这些规则很难记住,所以我更愿意让它明确。从技术上讲,这是UB。它导致溢出。有趣的是-我认为这是定义良好的。。。另一种方法是,将有符号字符强制转换为无符号字符。如果数字不能表示为有符号,则定义了无符号到有符号的实现。有符号到无符号变为“与源整数(模2^n)全等的最小无符号整数”。在二的补码表示中,这只是保持相同的位模式。参见4.7积分转换。@JohnPS:我明白了,谢谢。我编辑了答案,说它是实现定义的。从有符号到无符号的转换将保持位模式,因此有符号字符-50将变为无符号。从unsigned到signed将是相同的数字,如果它可以表示为signed,否则它是实现定义的;在我的平台上工作很好。对此很抱歉,但仍然非常感谢它给我的见解。@Sven de:是的,它可能是实现定义的,但大多数实现都会采取简单的方法(而不是将其饱和到+127的最大值)@Sven de:如果这是对你有用的答案,你能把它作为一个答案并接受它吗,或者接受Kerrek非常相似的回答并发表评论?当这个问题现在得到回答时,把它标记为还没有被接受的答案是令人困惑的。谢谢这违反了严格的别名&因此可以在程序之外进行优化,或者对其进行UBify。“重新解释”表示的唯一标准方法需要简单的可复制类型和
memcpy
到目标。希望编译器能将其优化为您一直想要的机器代码重新解释,但不能保证提供的是
重新解释
(可能很遗憾)。这是一个非常容易被误解的关键词,可能是因为严格的别名使得它几乎与期望值无关。例外情况是,
reinterpret\u cast
ing为
char
类型来读取表示总是有效的。@下划线\d我认为这是允许的“与对象的动态类型相对应的有符号或无符号类型的类型”。这可能只是我对该子句的误读。是的,似乎你是对的。谢谢你提醒我那一行的签名/未签名。然而,
reinterpret\u cast
在这里是不必要的,并且可能比简单的
静态\u cast
成功的可能性(保证)更低:……或者我只是在试图找到
reinterpret\u cast
如何在签名之间转换的规范时搜索失败?如果没有指定,我会假设它(A)做它想要的任何事情。。。或者至少(B)
static\u cast
所做的,在这种情况下,不需要指针往返。@下划线\d A
static\u cast
指针将失败,因为
uint8\u t
int8\u t
是不同的类型,因此这里需要
重新解释\u cast
。N3797说:“对象指针可以显式转换为不同类型的对象指针。”使用指针而不是值是因为原始问题表明无符号值和有符号值中的位模式必须相同。使用2的补码并不重要,但需要使用指针