如何使用 C++ 中的位操作从长变量中破译 4 个短变量?
Posted
技术标签:
【中文标题】如何使用 C++ 中的位操作从长变量中破译 4 个短变量?【英文标题】:How to decipher 4 short vars from a long var using bit manipulations in C++? 【发布时间】:2011-01-17 21:23:21 【问题描述】:long wxyz; //(w = bits 0-8, x = bits 9-17 , y = bits 18-23, z = bits 24-29)
short w;
short x;
short y;
short z;
w= wxyz & 0xFF800000;
x= wxyz & 0x007FC000;
y= wxyz & 0x00003F00;
z= wxyz & 0x000000FC;
这段代码正确吗?
谢谢
【问题讨论】:
一个可以“二进制”显示的计算器是你的朋友……那还有笔和纸 :P 但是,记住这只是一个面具。您需要将屏蔽位“移动”到正确的空间中。我更喜欢 shift 和 then mask,因为掩码更容易。此外,您根本不必担心符号扩展。 通常,位 0 表示最低有效位。您的公式使用位 0 作为最高有效位。如果这是预期的,那么您的公式似乎还可以。否则,您的位掩码不正确。是的,你必须移动提取的位。 请格式化您的代码。 【参考方案1】:您需要将位向下移动。
w= (wxyz & 0xFF800000) >> 23;
x= (wxyz & 0x007FC000) >> 14;
y= (wxyz & 0x00003F00) >> 8;
z= (wxyz & 0x000000FC) >> 2;
【讨论】:
您的班次金额不正确。第一个应该是 23,第二个应该是 14,第三个应该是 8,第四个应该是 2。 @mbaitoff:你是对的。我误读了这个问题,只是假设他想平均分配这些位(每个 8 个) 他说 w 是 0-8 位,你有它作为 23-31 位。 @ThomasMcLeod:这取决于您如何标记这些位。我通常按照我在纸上阅读它们的顺序标记它们,首先是最重要的数字,并且 OP 尚未指定,但根据他的面具,我们可以猜测他给它们贴上相同的标签。 @ThomasMcLeod:LSB 就是 LSB。将其标记为 0、31 还是 32 完全是任意的。就像我说的,根据 OP 的面具,他清楚地将其标记为 31。我基于此回答。纠正他的问题,我正在回答他的预期问题。【参考方案2】:您应该执行以下操作以从 4 字节 int w = (wxyz & 0xFF000000) >> 24
中获取最高字节。首先应用位掩码,然后将位移动到最低字节。
或者你也可以换一种方式——移位,应用位掩码:
w = (wxyz >> 24) & 0xFF
x = (wxyz >> 16) & 0xFF
y = (wxyz >> 8) & 0xFF
z = wxyz & 0xFF
但是使用联合不是更容易吗?
【讨论】:
没有。联合不能用于位操作,因为标准没有说明如何打包联合的元素。任何基于联合的解决方案都将是编译器和 CPU 特定的。 用 0xFF 或 0xFFFF 获得 short 类型的 var 吗? 他定义的位片不都是8位的。 联合的问题不在于标准是否规定了元素的布局方式,而是联合的所有元素共享>相同的内存空间:union U int x, y; ;
联合有两个字段,但都共享相同的内存,在这种情况下联合的大小将是sizeof(int)
。您无法控制内存布局,这不是解决方案。您可能一直在考虑 bitfields,它可以让您将不同的位解释为不同的变量,但实际上标准并未指定。【参考方案3】:
w = wxyz & 0x000001ff;
x = (wxyz & 0x0003fe00) >> 9;
y = (wxyz & 0x00fc0000) >> 17;
z = (wxyz & 0x3f000000) >> 23;
编辑:需要将 long 转换为 short 以避免编译器警告:
w = (short) wxyz & 0x000001ff;
x = (short) ((wxyz & 0x0003fe00) >> 9);
y = (short) ((wxyz & 0x00fc0000) >> 17);
z = (short) ((wxyz & 0x3f000000) >> 23);
【讨论】:
嗯,OP请忽略这个回复。 实际上我认为这个答案也是正确的,因为位 0 到 8 是最低有效位。 当时写评论是错的,后来又被编辑了好几次。【参考方案4】:等等——0-8 位是什么意思?这通常意味着九个最低有效位,在这种情况下,您掌握了 int 的错误结尾。
【讨论】:
我认为你是对的,位 0 到 8 是最低有效位。但我想感谢所有的回复,我现在至少有两种方法来处理它,但是我必须使用正确的长尾。【参考方案5】:这是我更喜欢通过“寸动”来处理这个问题的方式。这在我的脑海中更有意义。此外,与掩码和移位不同,没有问题,>> 符号扩展(C/C++ 不是 Java 或 C# 的明确定义)。如问题所述,我假设 0 是 MSB(总共有 32 位,尽管长 可以 更多)。
long wxyz = ...; //(w = bits 0-8, x = bits 9-17 , y = bits 18-23, z = bits 24-29)
wxyz >>= 2; // discard 30-31 (or, really, "least two insignificant")
z = wzyz & 0x3f; // easy to see this is "6 bits", no?
wzyz >>= 6; // throw them out
y = wzyz & 0x3f;
wzyz >>= 6;
x = wzyz & 0x1ff;
wzyz >>= 9;
w = wzyz & 0x1ff;
wzyz >>= 9; // for fun, but nothing consumes after
附:调整类型留给读者作为练习。
【讨论】:
你差了一英寸:) 最后一英寸应该与 0x1ff 相加并移动 9(为了好玩)。这是因为 0-8 的长度是 9。 @Michael Smith 绝对正确(问题已更新以反映);-) 我还应该添加“有效性测试留给读者作为练习”。【参考方案6】:这是您可以使用的不同解决方案。
long wxyz;
short w, x, y, z;
char* buf = new char[sizeof(long)];
buf = (char*)long; // cast long as byte array
w = (short)buf[0]; // The way you sort depends on endianness
x = (short)buf[1];
y = (short)buf[2];
z = (short)buf[3];
delete[] buf;
【讨论】:
【参考方案7】:部分正确。如果您想要每个段的值,则必须将它们向右移动。
short w = (short)((wxyz & 0xFF800000) >> 23);
short x = (short)((wxyz & 0x007FC000) >> 14);
short y = (short)((wxyz & 0x00003F00) >> 8);
short z = (short)((wxyz & 0x000000FC) >> 2);
这些是正确的值。
【讨论】:
@Michael Smith:These are correct values.
不,他们不是。例如,z 将始终等于 0 mod 4,这肯定不在原始规范中。
@TonyK:编辑 z 分配以将右值移动 2。立场纠正。但是我得到了最正确的分数:)
@Michael Smith:不,你没有。位 0-8 是最低有效位,而不是最高有效位。不要沾沾自喜。
@TonyK:来吧,要有幽默感。这是一个开放思想的开放论坛。当然 0-8 是最不重要的,但只需回答问题是如何提出的。
@Michael Smith:了解自己的局限性。 “这些是正确的价值观”。 “但是我得到最正确的分数。”这不会对我大喊“敞开心扉”!以上是关于如何使用 C++ 中的位操作从长变量中破译 4 个短变量?的主要内容,如果未能解决你的问题,请参考以下文章