在八位二进制补码中,符号位可以解释为位值 -2 8,当然是 -256。事实上,这正是 C 标准的特点。因此,给定一个存储在 a 中的 8 位值uint8_t
,您希望将其重新解释为二进制补码整数,这是一种算术方法:
uint8_t u8 = /* ... */;
int8_t i8 = (u8 & 0x7f) - (u8 > 0x7f) * 0x100;
请注意,所有算术都是通过首先将操作数提升为 (signed) 来执行的int
,因此既没有溢出(因为范围int
足够大)也没有无符号算术环绕。算术结果保证在 的范围内int8_t
,因此在将结果转换为该类型时也不存在溢出风险。
您会注意到此计算与您的计算之间的相似之处,但此计算通过u8 > 0x7f
在算术中直接使用关系表达式(0 或 1)的结果避免了三元运算符,从而避免了任何分支,并且它省去了不必要的强制转换。(你的也不需要演员表。)
另请注意,如果您遇到一些不提供的奇怪实现int8_t
(因为它char
的 s 比 8 位宽,或者它signed char
的 s 不使用二进制补码),那么该算术方法在计算正确值的意义上仍然有效,并且您可以确定在int
or中安全地记录该值short
。因此,提取uint8_t 的 8 位二进制补码解释值的绝对最便携的方法是
uint8_t u8 = /* ... */;
int i8 = (u8 & 0x7f) - (u8 > 0x7f) * 0x100;
或者,如果您愿意依赖于int8_t
成为字符类型——即char
或的别名signed char
——那么以这种方式完成工作是完全标准的:
uint8_t u8 = /* ... */;
int8_t i8 = *(int8_t *)&u8;
memcpy()
与另一个答案中提出的替代方案相比,编译器更有可能将其优化掉,但与memcpy
替代方案不同的是,如果int8_t
结果不是字符类型,则该方案正式具有未定义的行为。另一方面,这种方法和memcpy()
方法都依赖于提供 type 的实现int8_t
,甚至比不提供的实现更不可能int8_t
是实现提供的 anint8_t
不是字符类型。