K&R练习2-7中的位反转function
C编程语言的练习2-7:
写一个函数
invert(x,p,n)
,返回x
,其中n
位从位置p
开始反转(即1变为0,反之亦然),其他不变。
我理解这样的问题:我有182这是二进制的101(101)10
,括号中的部分必须反转而不改变其余部分。 返回值应为10101010
,即十进制为170。
这是我的尝试:
#include unsigned int getbits(unsigned int bitfield, int pos, int num); unsigned int invert(unsigned int bitfield, int pos, int num); int main(void) { printf("%d\n", invert(182, 4, 3)); return 0; } /* getbits: get num bits from position pos */ unsigned int getbits(unsigned int bitfield, int pos, int num) { return (bitfield >> (pos+1-n)) & ~(~0 << num); } /* invert: flip pos-num bits in bitfield */ unsigned int invert(unsigned int bitfield, int pos, int num) { unsigned int mask; unsigned int bits = getbits(bitfield,pos,num); mask = (bits << (num-1)) | ((~bits <> num); return bitfield ^ mask; }
这对我来说似乎是正确的,但是invert(182, 4, 3)
536870730
invert(182, 4, 3)
输出536870730
。 getbits()
工作正常(它直接来自书中)。 我写下了我分配给y
的表达式中发生的事情:
(00000101 << 2) | ((~00000101 <> 3) -- 000000101 is the part being flipped: 101(101)10 00010100 | ((11111010 <> 3) 00010100 | (01000000 >> 3) 00010100 | 00001000 = 00011100 10110110 (182) ^ 00011100 ---------- = 10101010 (170)
应该是正确的,但事实并非如此。 我发现这是出错的地方: ((~xpn <> n)
。 我不知道怎么样。
另外,我不知道这段代码有多普遍。 我的首要任务是让这个案子有效。 也欢迎这个问题的帮助。
将这个 当p大于单词大小(移位超过单词大小未定义)时仍然存在问题,但这应该是调用者的责任;-) 对于具有p = 2且n = 3的示例((1u<
<
p
位置的块移到左边。 (如果你想从左边算起,你应该用(pn)
而不是p移动)。
return val ^ (((1u<
101(101)10
:
1u<
我认为你在其中一个转变中有一个一个一个问题(这只是一个预感,我不完全确定)。 不过,我会保持简单(我假设索引位置p
从LSB开始,即p
= 0是LSB ):
unsigned int getbits(unsigned int x, int p, int n) { unsigned int ones = ~(unsigned int)0; return x ^ (ones << p) ^ (ones << (p+n)); }
编辑:如果你需要p = 0作为MSB ,只需反转移位(这可以正常工作,因为它们被定义为unsigned int
):
unsigned int getbits(unsigned int x, int p, int n) { unsigned int ones = ~(unsigned int)0; return x ^ (ones >> p) ^ (ones >> (p+n)); }
注意:在两种情况下,如果p < 0
, p >= sizeof(int)*8
, p+n < 0
或p+n >= sizeof(int)*8
,则getbits
的结果是未定义的。
看一下Steve Summit的“Introductory C programming”和Ted Jensen的“C指针和数组教程” 。 他们所涵盖的语言与今天的C语言略有不同(编程风俗也在不断发展,机器规模要大得多,真正的男人不再编写汇编程序),但他们所说的大部分内容都是如此真实。 肖恩安德森的“比特笨拙的黑客”将让你的眼睛膨胀。 保证。
我发现我的实现有什么问题(除了从错误的方向计数num
)。 之后看起来相当明显,我已经学到了更多关于比特的知识。
当1位向左移位时,超出位域的范围,它会扩展。
1000 (8) << 1 == 10000 (16)
bitfield << n
将bitfield
乘以2 n
次。 我的表达式((~bits << (pos+1)) >> num)
有5位,4位和3 bits
作为bits
, pos
和num
值。 我将一个几乎与32位int大小相乘的数字乘以2,两次。
我的function怎么样? 我觉得这很好。
unsigned invert(unsigned x,int p,int n) { return (x^((~(~0<