位移动,未签名的字符

bitwise shifts, unsigned chars

本文关键字:字符 移动      更新时间:2023-10-16

任何人都可以言行地解释这是什么完成的吗?我试图学习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变量可能是不正确的。

Bitwise-and &操作员比较双方两个操作数的位,如果两者都是1(true)(true),则返回1(true),而0(false)(false)(false)(false),如果任何或两个是0(false);它每一点都可以做到这一点。示例:

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)将评估到变量l的第一个4 * 8 - 24 = 8位,这是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的评估,这是临时的。

然后,0xff仅在十六进制中(基数16)中的0000 0000 0000 0000 0000 0000 1111 1111,与位移位的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在CC_34上具有相应的位。

我希望这会有所帮助,其余的事情像这样做了,所以...是的。从本机字节订单到标准网络(大端)字节订单。它们通过从天然值转移和掩盖8位块并将其存储到字节数组中来起作用。

如果我看正确,基本上是在短的和长时间切换字节的顺序...=" ans">

explain verbosely -OK ...

    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移动,结果存储在p[0]中。(p[0] == 0x12

  p[1] = s & 0xff;

现在请注意,当我们进行此轮班时,我们从未更改s的原始值,因此s仍然具有0x1234的原始值,因此,当我们执行第二行时,我们只是做另一个位,并且p[1]获得了sp[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。

右移。

功能的名称是一个很大的提示..." net short"answers" net net long"。

如果您考虑十进制...说我们有两张纸如此小,我们只能在每个纸上写一个数字,因此我们可以使用两者来记录从0到99:00,01的所有数字,02 ... 08,09,10,11 ... 18,19,20 ... 98,99。基本上,一张纸包含" Tens"柱(鉴于我们是小数的基本10),另一个"单位"。

记忆的工作原理,每个字节都可以存储0..255的数字,因此我们在基本256中工作。如果您有两个字节,其中一个将是"两百五十个-sixes"列,另一个"单位"列。要计算出合并的价值,您将前者乘以256并添加后者。

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

因此,某些计算机存储258-为1 * 256 2- as LOW = 1 high = 2,而其他计算机则存储低= 2高= 1。

这些函数的作用是从CPU碰巧使用的任何用来重新排列内存,即可预测的顺序 - 即,越重要的值(S)进入较低的内存地址,最终将"单位"值放入最高内存地址。这是存储所有计算机类型的数字的一致方法,因此,当您想通过网络传输数据时,这很棒。如果接收计算机对基本-256数字使用不同的内存排序,则可以将它们从网络字节订购转移到其喜欢的任何顺序上,然后再将其解释为CPU本地数字。

so," net short"将最重要的8位s包装到p[0]中 - 较低的存储器地址。实际上,它实际上不需要& 0xff,因为在服用16个输入位并将其转移到"右"之后,所有左手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)