在C / C ++中,有一种简单的方法可以将位运算符(特别是左/右移位)应用于动态分配的内存吗?
例如,假设我这样做了:
unsigned char * bytes=new unsigned char[3];
bytes[0]=1;
bytes[1]=1;
bytes[2]=1;
我想要一种方法:
bytes>>=2;
(然后'字节'将具有以下值):
bytes[0]==0
bytes[1]==64
bytes[2]==64
为什么值应该是这样的:
分配后,字节如下所示:
[00000001][00000001][00000001]
但我希望将字节视为一个长字符串,如下所示:
[000000010000000100000001]
右移2会导致比特看起来像这样:
[000000000100000001000000]
当分成3个字节(因此是0,64,64)时,最终看起来像这样:
[00000000][01000000][01000000]
任何想法?我是否应该制作一个结构/类并重载相应的运算符?编辑:如果是的话,有关如何进行的任何提示?注意:我正在寻找一种方法来实现这一点(有一些指导)作为学习经验。
答案 0 :(得分:2)
bitset
这样的标准容器是否能为您完成工作boost::dynamic_bitset
粗略的例子:
typedef unsigned char byte;
byte extract(byte value, int startbit, int bitcount)
{
byte result;
result = (byte)(value << (startbit - 1));
result = (byte)(result >> (CHAR_BITS - bitcount));
return result;
}
byte *right_shift(byte *bytes, size_t nbytes, size_t n) {
byte rollover = 0;
for (int i = 0; i < nbytes; ++i) {
bytes[ i ] = (bytes[ i ] >> n) | (rollover < n);
byte rollover = extract(bytes[ i ], 0, n);
}
return &bytes[ 0 ];
}
答案 1 :(得分:2)
正如John Knoeller建议的那样,我假设你想要从一个字节到下一个字节的位数。
这里的要求不足。您需要指定相对于字节顺序的位的顺序 - 当最低有效位超出一个字节时,会转到下一个较高字节或下一个较低字节。
您所描述的内容过去常常用于图形编程。您基本上已经描述了单色位图水平滚动算法。
假设“正确”意味着更高的地址但更低的有效位(即匹配两者的正常写入约定),单位移位将类似......
void scroll_right (unsigned char* p_Array, int p_Size)
{
unsigned char orig_l = 0;
unsigned char orig_r;
unsigned char* dest = p_Array;
while (p_Size > 0)
{
p_Size--;
orig_r = *p_Array++;
*dest++ = (orig_l << 7) + (orig_r >> 1);
orig_l = orig_r;
}
}
调整变量大小的代码应该不是一个大问题。有明显的优化机会(例如,一次做2个,4个或8个字节),但我会把它留给你。
要向左移动,你应该使用一个单独的循环,它应该从最高地址开始并向下工作。
如果要扩展“按需”,请注意orig_l变量包含上面的最后一个字节。要检查溢出,请检查(orig_l&lt;&lt;&lt; 7)是否为非零。如果你的字节在std :: vector中,那么在任何一端插入应该没问题。
编辑我应该说 - 优化一次处理2个,4个或8个字节会产生对齐问题。例如,当从未对齐的字符串数组中读取2字节字时,最好首先读取奇数字节,以便后面的字读取都在偶数地址处,直到循环结束。
在x86上,这不是必需的,但 要快得多。在某些处理器上,这是必要的。只需根据基数(地址&amp; 1),(地址&amp; 3)或(地址&amp; 7)进行切换,以便在循环之前处理开始时的前几个字节。您还需要特殊情况下主循环后的尾随字节。
答案 2 :(得分:1)
以下是我将如何处理两个字节:
unsigned int rollover = byte[0] & 0x3;
byte[0] >>= 2;
byte[1] = byte[1] >> 2 | (rollover << 6);
从那里,您可以将其概括为n个字节的循环。为了灵活性,您需要生成幻数(0x3和6)而不是硬编码。
答案 3 :(得分:1)
我会研究类似的事情:
#define number_of_bytes 3
template<size_t num_bytes>
union MyUnion
{
char bytes[num_bytes];
__int64 ints[num_bytes / sizeof(__int64) + 1];
};
void main()
{
MyUnion<number_of_bytes> mu;
mu.bytes[0] = 1;
mu.bytes[1] = 1;
mu.bytes[2] = 1;
mu.ints[0] >>= 2;
}
玩它吧。你会明白我的想法。
答案 4 :(得分:0)
运算符重载是语法糖。它实际上只是一种调用函数并传递字节数组的方法,而不是像调用函数一样看。
所以我首先要编写这个函数
unsigned char * ShiftBytes(unsigned char * bytes, size_t count_of_bytes, int shift);
然后,如果你想将它包装在一个运算符重载中以便更容易使用,或者因为你只是喜欢这种语法,你也可以这样做。或者你可以调用该函数。