C语言位编程:ipv4_to_bit_string()传参1234的移位逻辑解析
问题描述
我是C语言位编程的初学者,目前难以理解代码中ipv4_to_bit_string()函数的工作原理,核心疑问如下:
- 向该函数传入整数1234时具体会执行什么操作?
- 函数中为何要对传入的整数分别执行右移24位、16位、8位、4位的操作?
参考代码
#include <stdio.h> #include <string.h> #include <stdint.h> #include <stdlib.h> typedef struct BIT_STRING_s { uint8_t *buf; /* BIT STRING body */ size_t size; /* Size of the above buffer */ int bits_unused; /* Unused trailing bits in the last octet (0..7) */ } BIT_STRING_t; BIT_STRING_t tnlAddress; void ipv4_to_bit_string(int i, BIT_STRING_t *p) { do { (p)->buf = calloc(4, sizeof(uint8_t)); (p)->buf[0] = (i) >> 24 & 0xFF; (p)->buf[1] = (i) >> 16 & 0xFF; (p)->buf[2] = (i) >> 8 & 0xFF; (p)->buf[3] = (i) >> 4 & 0xFF; (p)->size = 4; (p)->bits_unused = 0; } while(0); } int main() { BIT_STRING_t *p = (BIT_STRING_t*)calloc(1, sizeof(BIT_STRING_t)); ipv4_to_bit_string(1234, p); }
解答
传入1234时的执行流程
传入参数i=1234时,函数按顺序执行以下操作:
- 为
p->buf分配4字节的堆内存,calloc会自动将这4字节初始化为0 - 逐字节计算并填充buf数组的4个元素:
1234作为32位int存储时的二进制为00000000 00000000 00000100 11010010,所有高于12位的比特位全为0:- 计算
buf[0]:将1234右移24位后,所有有效比特位都被移出,结果为0,和0xFF按位与后仍为0,因此buf[0] = 0 - 计算
buf[1]:将1234右移16位后,有效比特位同样被全部移出,结果为0,因此buf[1] = 0 - 计算
buf[2]:将1234右移8位后,剩余值为二进制00000100也就是十进制4,和0xFF按位与后为4,因此buf[2] =4 - 计算
buf[3]:将1234右移4位后,剩余值为二进制01001101也就是十进制77,和0xFF按位与后为77,因此buf[3] =77
- 计算
- 给结构体其他成员赋值:设置
p->size =4表示缓冲区长度为4字节,设置p->bits_unused=0表示最后一个字节没有闲置比特位 - 代码里的
do{...}while(0)是C语言常见的单段代码包裹写法,没有循环逻辑,只会执行一次包裹内的代码。
移位操作的设计逻辑
IPv4地址本质是一个32位无符号整数,我们平时用的点分十进制格式(比如192.168.1.1),本质是把32位整数拆成4个独立的8位段(每个段取值0-255),从高位到低位依次对应四个十进制数。
正常的IPv4拆分为字节数组的逻辑,就是通过移位把每个8位段移动到最低位,再通过&0xFF保留最低8位、清除高位多余值,对应关系是:
- 右移24位:取32位整数的最高8位,对应点分十进制的第一个段
- 右移16位:取32位整数的次高8位,对应点分十进制的第二个段
- 右移8位:取32位整数的第三个8位,对应点分十进制的第三个段
- 右移0位(即不做移位直接
&0xFF):取32位整数的最低8位,对应点分十进制的第四个段
你贴出的代码最后一步写的是右移4位,这是代码编写错误,会导致最后一个字节取值错误,无法正确解析出IPv4地址的第四段。
内容的提问来源于stack exchange,提问作者myquest4 sh
相关产品推荐
相关产品推荐

