任何人都可以详细解释这是什么意思吗?我试图学习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;
}
答案 0 :(得分:7)
详细地说,在这里:
直接回答;它们都从左到右将变量的字节存储在一个字节数组中。 tonet_short
对unsigned 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),则返回1
(true),{{1} }(false)如果其中任何一个或两个都是0
(false);它为每一位做到这一点。例如:
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;
为l
,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
的评估,这是暂时的。
然后,以十六进制(基数为16)为l >> 24
的{{1}}以逐位移位0xff
进行逐位求和。它是这样的:
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
的帮助下完成位。
我希望这会有所帮助,剩下的就像它到目前为止一样,所以......是的。
答案 1 :(得分:1)
这些例程将16位和32位值从本机字节顺序转换为标准网络(大端)字节顺序。它们通过从原生值移位和屏蔽8位块并将它们按顺序存储到字节数组中来工作。
答案 2 :(得分:0)
如果我看到它是正确的,我基本上切换短和长的字节顺序...(反转数字的字节顺序)并将结果存储在希望有足够空间的地址:)< / p>
答案 3 :(得分: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
)然后将其与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) )我们还要做一些额外的转变。
答案 4 :(得分:0)
此代码用于将16位或32位数字序列化为字节(uint8_t
)。例如,将它们写入磁盘,或通过网络连接发送它们。
16位值分为两部分。一个包含最高有效(高)8位,另一个包含最低有效(低)8位。首先存储最重要的字节,然后存储最不重要的字节。这称为大端或“网络”字节顺序。这就是函数命名为tonet_
。
对32位值的四个字节也是如此。
& 0xff
操作实际上是无用的。当16位或32位值转换为8位值时,低8位(0xff
)将被隐式屏蔽。
位移用于将所需字节移动到最低8位。考虑一个32位值的位:
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
最重要的字节是名为A
的8位。为了将它们移动到最低的8位,该值必须右移24。
答案 5 :(得分:0)
功能的名称是一个很大的暗示......“净短”和“净长”。
如果你考虑十进制...说我们有两张纸如此之小我们只能在每一张纸上写一个数字,因此我们可以用它们来记录从0到99:00,01的所有数字,02 ... 08,09,10,11 ...... 18,19,20 ...... 98,99。基本上,一张纸上有“十位”栏(假设我们的十进制数为10) ,另一个是“单位”。
内存的工作方式类似于每个字节可以存储0..255的数字,所以我们在256的基础上工作。如果你有两个字节,其中一个将是“二百五十” -sixes“列,另一个”单位“列。要计算出组合值,你将前者加倍256并添加后者。
在纸面上,我们在左边用更重要的数字编写数字,但在计算机上不清楚更重要的值是应该在更高还是更低的内存地址中,因此不同的CPU制造商选择了不同的约定。
因此,有些计算机存储258 - 1 * 256 + 2 - 低= 1高= 2,而其他计算机存储低= 2高= 1。
这些函数的作用是将内存从CPU正常使用的内容重新排列为可预测的顺序 - 即,更重要的值进入较低的内存地址,最终将“单位”值放入最高内存地址。这是存储适用于所有计算机类型的数字的一致方式,因此当您想通过网络传输数据时,它非常棒;如果接收计算机对base-256数字使用不同的内存顺序,它可以将它们从网络字节顺序移动到它喜欢的任何顺序,然后再将它们解释为CPU本机数字。
因此,“to net short”将s
中最重要的8位打包到p[0]
- 较低的内存地址。它实际上不需要& 0xff
,因为在取16个输入位并将它们8移到“右”之后,所有左手8位都保证为0,这是来自{{1}的影响。 } - 例如:
& 0xFF