首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在哪里可以找到C的一点移位指南?

在哪里可以找到C的一点移位指南?
EN

Stack Overflow用户
提问于 2009-01-14 15:01:46
回答 8查看 11.7K关注 0票数 6

我已经看过https://stackoverflow.com/questions/141525/absolute-beginners-guide-to-bit-shifting了,但是我仍然觉得比特移动的概念很难理解。

有人能为我指出一个更基本的C位移位指南的方向吗?我预计这将是一个很长的时间,因为它将需要涵盖整个问题。

我正在学习https://en.wikipedia.org/wiki/The_C_Programming_Language (AKA &R),这就是我的目的,所以我可以做练习。我理解基本知识,但我仍然不能做正确的位移位操作。

,这里是K&R的练习,让我很困惑,

练习2-6:编写函数集位(x,p,n,y),返回x,从位置p开始到y的最右边的n位,其他位不变。

练习2-7:编写一个函数倒置(x,p,n),返回从p位置开始的n位的x(即1改为0,反之亦然),而其他的则保持不变。

练习2-8:编写一个向右移动的函数(x,n),该函数返回整数x的值,该值由n个位位置向右旋转。

练习2-9:在两个补码系统中,x &= (x-1)删除x中最右边的1位。解释原因,并使用这一观察来编写更快版本的位计数。

这些都是k&R (C编程语言)书中的练习。这是最好的C书有,但我有困难的理解位移动,所以我有问题的这些练习。

EN

回答 8

Stack Overflow用户

发布于 2009-01-14 15:09:54

位移位只是字面意思:在给定的序列中左或右移动所有位。

您需要记住的是,每个十进制数(如6、7、3、2)都表示为计算机内存中的一个位序列。因此,如果在C代码中找到这样的东西:

代码语言:javascript
运行
复制
(7 >> 1)

这意味着基础二进制表示法7中的位将右移1位置。

我认为你引用的链接中的解释相当清楚。也许你自己在一张纸上写下一串比特,并像引用的链接中那样对它们进行操作,可能会有所帮助。

或者你可能还不可能理解计算机如何在内部与数字一起工作。在这种情况下,在学习比特移位之前,您需要阅读有关这方面的内容。

票数 8
EN

Stack Overflow用户

发布于 2009-01-14 15:58:54

你需要更多的工具来回答这些问题,而不是转移。

我想你需要开始非常基本的关于数字是如何用二进制表示的。然后,您将考虑如何设置和清除该数字中的特定位,或者同时清除一组位。您需要知道如何进行测试,以确定是否设置了某一组位,以及是否设置了掩蔽。您必须能够对按位运算符和,或,xor,反转等操作符进行上述操作。

然后你会想知道如何移动--移动的位,向左移动,向右移动,由特定数量的空格移动。你会想知道剩下的“空”部分会发生什么。里面是1还是0?它什么时候装满1或0?

谷歌的“按位操作教程”似乎一开始就产生了一些有希望的结果。但是,这里有一些基本知识可以用来测试你自己,以确保你明白

代码语言:javascript
运行
复制
// 1234 in hexadecimal. Do you understand this is not 1234 in decimal? Do you understand
// how specifying in hex makes it easier to think about the binary representation?
unsigned short i = 0x1234;
// Flip all the bits in 0x1234
printf("%04x", ~i);

// Test - Is the most significant bit set?
// mask is a binary number with the most significant bit set. Do
// you understand why this is so?
unsigned short mask = 0x8000;
if ((mask & i) == mask)
{
    printf("bit set!");
}
else
{
    printf("bit cleared!");
}

// Set the most significant bit
i = i | mask;
printf("Set the MSB of i, check it out: %i\n", i)

// Set the second most significant bit
// Do you see how by shifting mask right one it becomes the next most significant bit?
i = i | (mask >> 1);

祝好运!

票数 3
EN

Stack Overflow用户

发布于 2009-01-15 15:13:35

把这些部分写在纸上,考虑把它们从一端抹去,然后在另一端增加更多。和小学没什么不同,当小数点乘以10的时候移动小数点。

你所有的C函数都会把零移到。

所以

代码语言:javascript
运行
复制
x = y << 3;

意思是左移三位,右边的新位都是零。左边的三位进入“位桶”:

代码语言:javascript
运行
复制
x = z >> 2

失去右边的两个位,在左边加两个零。

你会发现,K&R演习是关于什么,缺失的功能。在处理器类型中,与C或任何其他高级语言相比,您具有更多的转换功能。

你有旋转函数,从一端移动的位在另一端被移动。

所以0xD以这种方式向右旋转一位是0xE,因为最不重要的位是1,所以向右移动1101,右边的1变成左1110的1。

有时,您通过阿鲁中的进位旋转。假设进位中有一个零,你旋转了0xD一位01101,剩下10110个0x6。再旋转一个,01011,得到一个0xB等等。

你为什么要在你要求的进位中旋转?对于更大的数字,假设您有四位寄存器,并希望进行8位移位,假设每个字母都是位( bcde ),其中a是进位位,其余两组是4位寄存器。首先旋转左寄存器通过进位e abcd fghi,然后旋转右寄存器通过进位i abcd efgh。非常酷,我们刚做了一个8位移位和一个4位移位功能。

如果您在启动之前清除了进位(通常会有这样的指令,或者您总是可以执行一些类似于添加0+0或其他保证清除该位的操作)。

I0bcd efgh

这与C移位函数在32位指令集上操作64位数时所做的没有什么不同。

处理器通常有C类移位,其中零被移动,移位abcd左一给bcd0移位abcd右二给00ab。

这会给那些拥有现代处理器的年轻人带来一些问题。考虑这样的事情,因为整数除法在它们的处理器上都是支持的,并且可以在一个时钟周期内工作。在我们进行除法之前,或者当除法是几十到数百个时钟时,但是一个移位就是一个时钟,你可以用移位来完成你所有的2除法或乘法。取数字0x0D移位,剩下两个,得到0b00001101 << 2= 0b00110100或0x34。0xD是小数点13,0x34是小数点52。52是13的4倍多。4等于2乘以2。相移2等于乘4。

这是双向的;0x34右移2是0xD,但问题是。当你进入负数的时候,取数字-4 0xFC,然后除以2。使用C0xFC >> 1可以得到0x7E,但是0x7E是+126小数点。怎么-4/2 = 126?

问题是C移位为零。您会发现一些处理器有一个与逻辑移位不同的算术移位。算术移位保持最高位,所以如果你使用的是一个有符号的数字,比如0bQWER,你算术地移动了那个右位,你得到了0bQQwe。最上层的位既移到下一个位,又停留在原来的位置。

再次移动0 0bQQQW等。现在,算术左移将以零移动,而不是最不重要的位,所以0bQWER左移1是0bWER 0。这是合理的。-4左移一个是0xF8,是-8,-4乘以2是-8,所以这是对的。

因此,您会发现,有些处理器只有一个算术移位右,但没有左。有些允许您指定asl,但是当他们组装它时,用lsl (逻辑移位左)代替它,谁知道有些人实际上可能有一个单独的操作码,即使它是相同的功能。我想可能有一些有asl,asr和lsr,但没有lsl。

用纸和铅笔把事情弄清楚。先以实数作为例子,然后进行抽象。想要将0x1234旋转到右边一位,比方说?

代码语言:javascript
运行
复制
0001001000110100  write out the bits
x0001001000110100 shift right one
0000100100011010  because this is a rotate fill in the new bit with the bit that fell off on the prior operation

现在要把两位移到右边

代码语言:javascript
运行
复制
0000100100011010
xx0000100100011010
1000001001000110

我将如何在C中做一个位旋转?

代码语言:javascript
运行
复制
unsigned int rotate_right_one ( unsigned int x )
{
  unsigned int y;
  y = x & 1;  // Save the bit that is about to fall off the right
  x >> = 1;  // Logical rotate one bit
  x |= y<<31; // This assumes that unsigned int is 32 bits.
  return(x);
}

要旋转更多,您可以简单地多次调用此函数,或者考虑一下掩码和移位,以及它如何工作超过一位。

还请注意,一些处理器只有一个旋转函数。例如,想想这个。我有一个四位寄存器,我旋转5位。我能得到什么?

代码语言:javascript
运行
复制
abcd
bcda  first rotate
cdab  second
dabc  third
abcd  fourth
bcda  fifth

左转看上去是什么样子的?

代码语言:javascript
运行
复制
abcd
bcda  one bit left.

4位寄存器上的右5与左5-4=1相同。像asl一样,一些处理器将允许您对操作进行编码,但是汇编程序使用nbits shift作为旋转量来替换该操作。

对于一些人来说,逻辑位操作很难理解,但它是基本的,如果你学习并使用它,你将领先于你的竞争对手或你周围的人。

下面是一个计算某个变量中位数的示例:

代码语言:javascript
运行
复制
for(count=0, r=1; r; r<<=1) 
    if(r&some_variable) 
        count++;

理解这一行代码,您就可以很好地学习C和逻辑位操作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/443265

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档