繁体   English   中英

按位移位,无符号字符

[英]bitwise shifts, unsigned chars

任何人都可以详细解释这完成了什么? 我试图学习c并且很难绕过它。

void tonet_short(uint8_t *p, unsigned short s) {
  p[0] = (s >> 8) & 0xff;
  p[1] = s & 0xff;
}

void tonet_long(uint8_t *p, unsigned long l)
{
  p[0] = (l >> 24) & 0xff;
  p[1] = (l >> 16) & 0xff;
  p[2] = (l >> 8) & 0xff;
  p[3] = l & 0xff;
}

详细地说,这里是:

作为直接的答案; 它们都从左到右将变量的字节存储在一个字节数组中。 tonet_shortunsigned short变量执行此操作,该变量由2个字节组成; tonet_long用于unsigned long变量,由4个字节组成。

我将为tonet_long解释它,而tonet_short将只是你希望能够自己得出它的变体:

unsigned变量,当它们的位被逐位移位时,使它们的位向确定的一侧移位以确定比特量,并使空出的位为0 ,零。 即:

unsigned char asd = 10; //which is 0000 1010 in basis 2
asd <<= 2;              //shifts the bits of asd 2 times towards left
asd;                    //it is now 0010 1000 which is 40 in basis 10

请记住,这是一个unsigned变量,而这些可能是不正确的signed的变量。

按位和&操作者在两侧的两个操作数的位进行比较,返回1 (真),如果两者都是1 (真),和0 (假)如果它们中的任何一个或两者都是0 (假); 它为每一位做到这一点。 例:

unsigned char asd = 10; //0000 1010
unsigned char qwe = 6;  //0000 0110
asd & qwe;              //0000 0010 <-- this is what it evaluates to, which is 2

现在我们知道了按位移位和按位 - 并且,让我们到达函数tonet_long的第一行:

p[0] = (l >> 24) & 0xff;

这里,由于lunsigned long ,则(l >> 24)将被评估为第一4 * 8 - 24 = 8的可变的比特l ,这是第一个字节的l 我可以像这样想象这个过程:

abcd efgh   ijkl mnop   qrst uvwx   yz.. ....   //letters and dots stand for
                                                //unknown zeros and ones
//shift this 24 times towards right
0000 0000   0000 0000   0000 0000   abcd efgh

注意我们不改变l ,这只是l >> 24的评估,这是暂时的。

然后,以十六进制(基数16)为0000 0000 0000 0000 0000 0000 1111 11110xff以逐位移位的l进行逐位求和。 它是这样的:

0000 0000   0000 0000   0000 0000   abcd efgh
&
0000 0000   0000 0000   0000 0000   1111 1111
=
0000 0000   0000 0000   0000 0000   abcd efgh

因为a & 1将完全依赖于a ,所以它将是a ; 其余的一样......看起来这是一个多余的操作,而且确实如此。 然而,对其他人来说,这一点很重要。 这是因为,例如,当您评估l >> 16 ,它看起来像这样:

0000 0000   0000 0000   abcd efgh   ijkl mnop

由于我们只需要ijkl mnop部分,我们必须丢弃abcd efgh ,这将在0000 0000的帮助下完成, 0xff在其相应的位上。

我希望这会有所帮助,剩下的就像它到目前为止一样,所以......是的。

这些例程将16位和32位值从本机字节顺序转换为标准网络(大端)字节顺序。 它们通过从原生值移位和屏蔽8位块并将它们按顺序存储到字节数组中来工作。

如果我看到它正确,我基本上切换短和长的字节顺序...(反转数字的字节顺序)并将结果存储在希望有足够空间的地址:)

explain verbosely - 好的......

    void tonet_short(uint8_t *p, unsigned short s) {

short通常是16位值(最大值:0xFFFF)
uint8_t是无符号的8位值, p是指向某些无符号8位值的指针(来自我们假设至少2个连续值的代码)。

  p[0] = (s >> 8) & 0xff;

这将取s值的“上半部分”并将其放在数组p的第一个元素中。 所以我们假设s==0x1234
首先将s移位8位( s >> 8 == 0x0012
那么它与0xFF AND运算,结果存储在p[0] p[0] == 0x12

  p[1] = s & 0xff;

现在请注意,当我们执行该移位时,我们从未更改s的原始值,因此s仍然具有0x1234的原始值,因此当我们执行第二行时,我们只是执行另一个逐位AND并且p[1]得到s的值的“下半部分”( p[0] == 0x34

这同样适用于你在那里的其他功能,但它是一个long而不是短,所以我们假设在这种情况下p有足够的空间用于所有32位(4x8),我们也必须做一些额外的移位。

此代码用于将16位或32位数字序列化为字节( uint8_t )。 例如,将它们写入磁盘,或通过网络连接发送它们。

16位值分为两部分。 一个包含最高有效(高)8位,另一个包含最低有效(低)8位。 首先存储最重要的字节,然后存储最不重要的字节。 这称为大端或“网络”字节顺序。 这就是函数名为tonet_的原因。

对于32位值的四个字节也是如此。

& 0xff操作实际上是无用的。 当16位或32位值转换为8位值时,低8位( 0xff )被隐式屏蔽。

位移用于将所需字节移动到最低8位。 考虑32位值的位:

AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD

最重要的字节是名为A的8位。 为了将它们移动到最低的8位,该值必须右移24。

功能的名称是一个很大的提示......“净短”和“净长”。

如果你考虑十进制...说我们有两张纸如此之小我们只能在每一张纸上写一个数字,因此我们可以用它们来记录从0到99:00,01,02的所有数字。 .. 08,09,10,11 ...... 18,19,20 ...... 98,99。基本上,一张纸上有“十位”栏(假设我们的十进制数为10),其他的“单位”。

内存的工作方式类似于每个字节可以存储0..255的数字,所以我们在256的基数上工作。如果你有两个字节,其中一个将是“二百五十六”列,另一个是“单位”列。 要计算出组合值,您将前者加倍256并添加后者。

在纸面上,我们在左边用更重要的数字写数字,但是在计算机上不清楚更重要的值是应该在更高还是更低的内存地址中,因此不同的CPU制造商选择了不同的约定。

因此,一些计算机存储258 - 其为1 * 256 + 2 - 低= 1高= 2,而其他计算机存储低= 2高= 1。

这些函数的作用是将内存从CPU正常使用的内容重新排列为可预测的顺序 - 即,更重要的值进入较低的内存地址,最终将“单位”值放入最高的内存地址。 这是存储适用于所有计算机类型的数字的一致方式,因此当您想通过网络传输数据时,它非常棒; 如果接收计算机对base-256数字使用不同的内存排序,它可以将它们从网络字节顺序移动到它喜欢的任何顺序,然后将它们解释为CPU本机数字。

因此,“to net short”将最重要的8位s打包到p[0] - 较低的内存地址。 它实际上并不需要& 0xff因为在取16个输入位并将它们8移到“右”之后,所有左手8位都保证为0,这是来自& 0xFF的影响 - 例如:

      1010 1111 1011 0111  // = decimal 10*256^3 + 15*256^2 + 11*256 + 7
>>8   0000 0000 1010 1111 // move right 8, with left-hand values becoming 0
 0xff 0000 0000 1111 1111 // we're going to and the above with this
 &    0000 0000 1010 1111 // the bits that were on in both the above 2 values
                          // (the and never changes the value)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM