是否有一种可移植且安全的方式将boost::uint16_t
的位模式解释为boost::int16_t
?我有uint16_t
,我知道它代表一个带符号的16位整数,编码为little-endian。我需要对这个值做一些带符号的算术运算,所以无论如何都要说服编译器它已经是一个带符号的值吗?
如果我没有弄错的话,static_cast<int16_t>
会转换该值,或许会更改其位模式。
答案 0 :(得分:2)
如果您正在寻找与强制转换不同的内容,请将其内存表示形式复制到boost::int16_t
的内存表示形式,因为它的开头代码是什么。
编辑:如果必须在大端机器上运行,只需向后复制字节即可。使用std::copy
和std::reverse
。
答案 1 :(得分:1)
只需使用静态演员表。如果您恰好位于以不同方式定义它们的平台上,那么更改位模式恰好就是您想要的。
reinterpret_cast或任何等效的指针强制转换是未定义的(未实现定义)。这意味着编译器可以自由地执行令人讨厌的事情,例如将未定义的表单缓存在寄存器中并错过更新。此外,如果你在一个比特模式不同的平台上,那么绕过转换就会给你带来垃圾(就像假装一个浮点数是一个int并为它加1)。
更多信息位于Signed to unsigned conversion in C - is it always safe?但是汇总C以迂回的方式定义静态强制转换(实际上是普通的C cast),正是通过在x86上处理相同的位来实现的(使用两个&# 39;补充。)
不要在编译器中玩鸡(这总是适用于这个编译器,所以他们肯定不会通过更改它来打破每个人的代码)。历史证明你错了。
答案 2 :(得分:0)
屏蔽除符号位以外的所有内容,将其存储在有符号的int中,然后使用符号位设置符号。
答案 3 :(得分:0)
我猜*(boost::int16_t*)(&signedvalue)
可行,除非你的系统架构默认不是小端。 endian ness将改变行为,因为在上面的操作之后,cpu会将签名值视为体系结构特定的 boost :: int16_t值(意味着如果你的体系结构是大端的,它就会出错)。
答案 4 :(得分:0)
修改强>
为了避免对*(int16_t)(&input_value)
的争议,我将代码块中的最后一个语句更改为memcpy
,并添加了*(int16_t)(&input_value)
作为附录。 (反过来说。)
在大端机器上,您需要进行字节交换,然后解释为有符号整数:
if (big_endian()) {
input_value = (uint16_t)((input_value & 0xff00u) >> 8) |
(uint16_t)((input_value & 0x00ffu) << 8);
}
int16_t signed_value;
std::memcpy (&signed_value, &input_value, sizeof(int16_t));
在大多数计算机上,您可以将通话更改为memcpy
至signed_value = *(int16_t)(&input_value);
。严格地说,这是未定义的行为。它也是一种使用极为广泛的习语。几乎所有编译器都使用此语句执行“正确的事情”。但是,与语言的扩展一样,YMMV。
答案 5 :(得分:0)
作为一种不同的方法,最大化(但不能确保)可移植性的最佳方法是将那些带符号的16位整数存储为网络顺序中的带符号16位整数,而不是以小端顺序存储为无符号16位整数。这使得目标机器的负担能够将这些16位网络顺序有符号整数转换为本机形式的16位有符号整数到目标。并非每台机器都支持此功能,但大多数可以连接到网络的机器都支持此功能。毕竟,该文件必须通过某种机制到达目标机器,因此理解网络顺序的几率非常高。
另一方面,如果您通过某些专有的串行接口将该二进制文件切换到某个嵌入式计算机,那么可移植性问题的答案与您告诉医生时会得到的答案相同“当我这样做时会受到伤害此“。