3

谁能详细解释这是做什么的?我正在尝试学习 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;
}
4

6 回答 6

7

详细地说,这里是:

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

我将解释它tonet_long,并且tonet_short只是它的变体,您希望能够自己得出:

unsigned变量,当它们的位被按位移位时,将它们的位向确定的一侧移动以确定数量的位,并且空出的位被设为0零。IE:

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(true),则返回 (true),0如果其中任何一个或两者都为(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;

在这里,由于lis unsigned 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,这是暂时的。

然后,0xff它只是0000 0000 0000 0000 0000 0000 1111 1111十六进制(以 16 为底),与 bitwise-shifted 进行按位与运算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 00000xff

我希望这会有所帮助,其余的事情就像到目前为止一样,所以......是的。

于 2014-03-07T20:06:11.113 回答
1

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

于 2014-03-07T19:50:45.373 回答
0

如果我没看错,我基本上会在短字节和长字节中切换字节顺序......(颠倒数字的字节顺序)并将结果存储在一个希望有足够空间的地址:)

于 2014-03-07T19:34:25.347 回答
0

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)
,然后与它进行 AND0xFF运算,结果存储在p[0]. ( p[0] == 0x12)

  p[1] = s & 0xff;

现在请注意,当我们进行移位时,我们从未改变 的原始值s,因此s仍然具有 的原始值0x1234,因此当我们执行第二行时,我们只需执行另一个按位与并p[1]获得值的“下半部分” ( s)p[0] == 0x34

这同样适用于您在那里拥有的其他功能,但它是 along而不是 short,所以我们假设p在这种情况下有足够的空间容纳所有 32 位(4x8),我们也必须做一些额外的转变。

于 2014-03-07T19:51:05.750 回答
0

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

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

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

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

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

AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD

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

于 2014-03-07T19:55:04.700 回答
0

函数的名称是一个很大的提示......“净空头”和“净多头”。

如果您考虑十进制...假设我们有两张纸这么小,我们只能在每张纸上写一个数字,因此我们可以使用两者来记录从 0 到 99 的所有数字:00、01、02。 .. 08, 09, 10, 11... 18, 19, 20...98, 99。基本上,一张纸包含“十”列(假设我们以 10 为底数表示十进制),而其他“单位”。

内存的工作方式是这样的,每个字节可以存储一个从 0..255 开始的数字,所以我们以 256 为基数工作。如果你有两个字节,其中一个将是“256”列,另一个是“单位”列。要计算组合值,请将前者乘以 256 并添加后者。

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

因此,一些计算机将 258(即 1 * 256 + 2)存储为 low=1 high=2,而其他计算机存储 low=2 high=1。

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

因此,“to net short”将最重要的 8 位打包sp[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)
于 2014-03-07T19:59:54.280 回答