我有两个16位短路(s1和s2),我正在尝试将它们组合成一个32位整数(i1)。根据我正在处理的规范,s1是最重要的单词,而s2是最不重要的单词,并且组合单词似乎是签名的。 (即s1的最高位是符号。)
组合s1和s2的最简洁方法是什么?
我想像
const utils::int32 i1 = ((s1<<16) | (s2));
会这样做,而且似乎有效,但我担心左移16分。
另外,我对使用工会做这项工作的想法很感兴趣,对这是一个好主意还是坏主意有任何想法?
答案 0 :(得分:13)
如果short和int都是无符号的,那么你所做的只有意义。如果其中一个短路是有符号且具有负值,那么将它们组合成单个int的想法是没有意义的,除非您已经提供了特定于域的规范来涵盖这种可能性。
答案 1 :(得分:6)
你所看到的几乎是正确的,但如果第二部分是否定的话可能会失败;隐式转换为int可能会签名扩展并用1填充高16位。对无符号短路的转换可能会阻止这种情况发生,但最好的方法是屏蔽掉这些位。
const utils::int32 combineddata = ((data.first<<16) | ((data.second) & 0xffff));
答案 2 :(得分:5)
我知道这是一个很老的帖子,但目前发布的答案的质量令人沮丧......
这些是需要考虑的问题:
int
的操作数被签名。无论小整数类型的签名如何,都会发生这种情况。整数提升发生在班次操作和按位OR中。因此,正确的解决方案是:
看起来像这样:
int32_t i32 = (int32_t)( (uint32_t)s1<<16 | (uint32_t)s2 );
任何其他解决方案都非常值得怀疑,最多也是非便携式的。
答案 3 :(得分:3)
由于没人发布,这就是联盟的样子。但关于endian-ness的评论肯定适用。
大端:
typedef union {
struct {
uint16_t high;
uint16_t low;
} pieces;
uint32_t all;
} splitint_t;
小端:
typedef union {
struct {
uint16_t low;
uint16_t high;
} pieces;
uint32_t all;
} splitint_t;
答案 4 :(得分:1)
尝试将data.second explicite投影到短类型,例如:
const utils::int32 combineddata = ((data.first<<16) | ((short)data.second));
编辑:我是C#dev,可能你的代码语言中的转换看起来不一样,但想法可能是相同的。
答案 5 :(得分:0)
您希望在执行转换之前将data.first转换为int32,否则转移将在存储被分配到组合数据时自动升级之前溢出存储。
尝试:
const utils::int32 combineddata = (static_cast<utils::int32>(data.first) << 16) | data.second;
这当然假设data.first和data.second是保证精确16位长的类型,否则你会遇到更大的问题。
我真的不明白你的陈述“如果data.second变得太大,|将不会考虑到它们都是短路的事实。”
编辑: Neil对签名绝对正确。
答案 6 :(得分:-1)
使用union来完成这项工作看起来是个不错的选择,但由于处理器的字节差异而导致可移植性问题。它是可行的,但您需要准备好根据目标体系结构修改联合。位移是可移植的,但请编写一个函数/方法来为您完成。如果你愿意,可以内联。
关于短裤的签名,对于这种类型的操作,重要的不是数据类型。换句话说,如果s1和s2意味着被解释为32位字的两半,那么只有当你做一些会导致s2被符号扩展的东西时才设置第15位。请参阅Mark Ransoms答案,这可能会更好
inline utils::int32 CombineWord16toLong32(utils::int16 s1, utils::int16 s2)
{
return ((s1 <<16) | (s2 & 0xffff));
}