有人能给我解释一下这行C代码(指针运算,位移位)吗?

cygmwpex  于 2023-02-18  发布在  其他
关注(0)|答案(5)|浏览(91)

假设*c为内存中的32位,xmc[]为内存中的32位数组(摘要:网络数据包)

xmc[0] = (*c >> 4) & 0x7;
xmc[1] = (*c >> 1) & 0x7;
xmc[2] = (*c++ & 0x1) << 2;
xmc[2] |= (*c >> 6) & 0x3;
xmc[3] = (*c >> 3) & 0x7;

代码行xmc[2]对Value做了什么(以二进制考虑)?
我试着查算术题,但我没能理解从*c++开始的部分。
编辑:添加了更多上下文以进行澄清

hrysbysz

hrysbysz1#

    • 解引用和递增:**首先,获取存储在c指针所指地址的值,并递增该地址。
    • 带掩码的位与:**位与(&)是用值0x1(十进制1)的掩码执行的,这意味着仅从存储在地址c的值中取出最低有效位。

你可以这样想:您可以有一个4位变量,称为a,其十进制值为3(二进制0011),并且您正在a和十进制值2(二进制10)的掩码之间执行逐位AND,也是4位(因此0010):
a = 0011
b = 0010
位与(a & ba & (0x10))将计算ab中每两位之间的AND。a中的第一位为1b中的第一位为0 =〉结果中的最低有效位为1 & 0 = 0,继续每个变量的第二位,导致结果中的第二最低有效位为1等等。
带有此类掩码的AND通常用于从存储在变量中的值中获取特定位(或一组位)。在您的情况下,代码将获取存储在a中的最低有效位。

    • 左移:**左移<<将最低有效位向左移两个位置(例如,从00010100),将0上的2位向右添加。
xienkqul

xienkqul2#

假设我们对一个无符号的32位值进行运算。

xmc[2] = (*c++ & 0x1) << 2;

相当于

uint32_t tmp1 = *c;          // Read the value that c points to and
c = c + 1;                   // increment the pointer c
                             // These two lines is the *c++ part

uint32_t tmp2 = tmp1 & 0x1;  // Make tmp2 equal to the least significant bit of tmp1
                             // i.e. tmp2 will be 1 if tmp1 is odd and
                             // tmp2 will be 0 if tmp1 is even

uint32_t tmp3 = tmp2 << 2;   // Make tmp3 equal to tmp2 shifted 2 bits to the left
                             // This is the same as:  tmp3 = tmp2 * 4

xmc[2] = tmp3;               // Save the result in xmc[2]

在伪代码中,这意味着:

If the value pointed to be c is odd, set xmc[2] to 4
If the value pointed to be c is even, set xmc[2] to 0
Increment the pointer c
gkl3eglg

gkl3eglg3#

今天的日期可以说是20230215。
如果您将其作为一个数字,则可以按如下方式提取组件:

n = 20230215;

y = n / 10000 % 10000;
m = n /   100 %   100;
d = n /     1 %   100;

上面的代码也做了同样的事情,它提取分布在两个字节上的四个值(abcd)。

c[0]                              c[1]
  7   6   5   4   3   2   1   0     7   6   5   4   3   2   1   0
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
|   | a | a | a | b | b | b | c | | c | c | d | d | d |   |   |   |
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+

因为我们想提取比特而不是数字,所以我们需要使用2的幂而不是10的幂,当处理2的幂时,>>可以用来代替除法,&可以用来代替%
要提取abcd,我们可以使用以下代码:

n = ( c[0] << 8 ) | c[1];

xmc[0] = ( n >> 12 ) & 0x7;
xmc[1] = ( n >>  9 ) & 0x7;
xmc[2] = ( n >>  6 ) & 0x7;
xmc[3] = ( n >>  3 ) & 0x7;

发布的代码采用了一种避免计算n的方法,但它做的是同样的事情。

pxyaymoc

pxyaymoc4#

++是C语言中的一个后增量运算符,它将是在=左边赋值之前的最后一个运算。

xmc[2] = (*c++ & 0x1) << 2;

这一声明可被视为:
1.取消引用:*c
1.位与:*c & 0x1
1.左移:(*c & 0x1) << 2
1.增量后:c++
1.分配到=的左侧:xmc[2] =为第3步的结果。
但是,编译器将通过其设计优化这些操作,并可能通过利用CPU的寄存器和内存中的堆栈在按位AND操作之前增加c,即可能在最终汇编代码中发现差异。

oyxsuwqo

oyxsuwqo5#

发布的代码可以更容易阅读,如果它是,相当于:

xmc[0]  = (c[0] >> 4) & 0x7;
xmc[1]  = (c[0] >> 1) & 0x7;
xmc[2]  = (c[0]       & 0x1) << 2;
xmc[2] |= (c[1] >> 6) & 0x3;
xmc[3]  = (c[1] >> 3) & 0x7;

(And然后,如果后面的代码依赖于c被推进,则这之后可以是独立的c++。)
看起来xmc[0]取自c[0]的三个特定位,而xmc[1]取自c[0]的三个其它位。然后下一个字段跨越字边界,因为xmc[2]是通过将c[0]中的一个位放在一起而组成的。并且从c[1]中取出两个位。最后,从c[1]的其它三个位中取出xmc[3]
@池上的回答有更多细节。

相关问题