好的,我试着在C中写一个函数来反转一个长的(64字节),并且我得到了一些奇怪的位移位结果。
long reverse_long(long x) {
int i;
for(i=0; i<4; i++) {
long a = 0x00000000000000FF<<(8*i);
long b = 0xFF00000000000000>>(8*i);
a = x&a;
b = x&b;
a=a<<8*(7-2*i);
b=b>>8*(7-2*i);
x=x&(~(0x00000000000000FF<<(8*i)));
x=x&(~(0xFF00000000000000>>(8*i)));
x=x|a;
x=x|b;
}
}在第4行(long a = 0x00000000000000FF<<(8*i)),我在循环的每次迭代中将一个字节的1向左移动8位,这对于第一次、第二次和第三次迭代都很好,但是在第四次迭代时,我得到了类似0xFFFFFFFF000000的东西,而我应该得到0x00000000FF000000。
不过,第5行(long b = 0x00000000000000FF>>(8*i))运行得很好,并给出了值0x000000FF00000000。
有人能告诉我这是怎么回事吗?
发布于 2015-01-24 10:50:42
a)关于您的错误:
你在那里做什么:
long a = 0x00000000000000FF<<(8*i);it将其赋给长有符号,执行符号扩展: 0xFF000000 -> extension
b)关于你的代码:有更简单的方法来编写你的函数,例如:
unsigned long reverse_long(unsigned long x) {
unsigned long rc = 0;
int i = 8;
do {
rc = (rc << 8) | (unsigned char)x;
x >>= 8;
} while(--i);
return rc;
}发布于 2015-01-24 11:33:25
要了解代码中的潜在问题,您需要了解以下内容:
这是相当多的事情需要记住。为了避免处理各种奇怪的问题(例如,当使用i == 3时,long a = 0x00000000000000FF<<(8*i);会导致未定义的行为),我建议使用以下方法:
类型的正确宽度的x)
此外,您的代码假定long是64位的。这并非总是正确的。最好是做以下两件事之一:
unsigned long,无论unsigned long的大小是什么,请使用uint64_t简而言之,如果我们只是修复与我上面列出的点相关的错误(并且不更改算法),那么您的代码应该是这样的:
uint64_t reverse_long(uint64_t x)
{
int i;
for(i=0; i<4; i++)
{
uint64_t a = 0xFFull << (8*i);
uint64_t b = 0xFF00000000000000ull >> (8*i);
a = x&a;
b = x&b;
a=a<<8*(7-2*i);
b=b>>8*(7-2*i);
x=x&(~(0xFFull<<(8*i)));
x=x&(~(0xFF00000000000000ull>>(8*i)));
x=x|a;
x=x|b;
}
return x; // don't forget this
}注意:我已经使用ull后缀创建了64位文字。实际上,这只保证了至少64位,但由于这里的所有内容都是无符号的,所以没有区别,多余的位将被截断。更准确地说,用(uint64_t)0xFF代替0xFFull,等等。
发布于 2015-01-24 11:51:09
您已经收到了关于代码哪里出错的很好的建议,但我认为您可能希望看到另一种更简单的逆转方法。
uint64_t reverse_long(uint64_t n) {
uint8_t* a = (uint8_t*)&n;
uint8_t* b = a + 7;
while(a < b) {
uint8_t t = *b;
*b-- = *a;
*a++ = t;
}
}https://stackoverflow.com/questions/28121740
复制相似问题