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)输出536870730getbits()工作正常(它直接来自书中)。 我写下了我分配给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) 。 我不知道怎么样。

另外,我不知道这段代码有多普遍。 我的首要任务是让这个案子有效。 也欢迎这个问题的帮助。

((1u<是在RHS处具有n'1'位的位掩码。 <将这个p位置的块移到左边。 (如果你想从左边算起,你应该用(pn)而不是p移动)。

 return val ^ (((1u< 

当p大于单词大小(移位超过单词大小未定义)时仍然存在问题,但这应该是调用者的责任;-)

对于具有p = 2且n = 3的示例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 < 0p >= sizeof(int)*8p+n < 0p+n >= sizeof(int)*8 ,则getbits的结果是未定义的。

看一下Steve Summit的“Introductory C programming”和Ted Jensen的“C指针和数组教程” 。 他们所涵盖的语言与今天的C语言略有不同(编程风俗也在不断发展,机器规模大得多,真正的男人不再编写汇编程序),但他们所说的大部分内容都是如此真实。 肖恩安德森的“比特笨拙的黑客”将让你的眼睛膨胀。 保证。

我发现我的实现有什么问题(除了从错误的方向计数num )。 之后看起来相当明显,我已经学到了更多关于比特的知识。

当1位向左移位时,超出位域的范围,它会扩展。

  1000 (8) << 1 == 10000 (16) 

bitfield << nbitfield乘以2 n次。 我的表达式((~bits << (pos+1)) >> num)有5位,4位和3 bits作为bitsposnum值。 我将一个几乎与32位int大小相乘的数字乘以2,两次。

我的function怎么样? 我觉得这很好。

 unsigned invert(unsigned x,int p,int n) { return (x^((~(~0<