在看一个构造ip包头的的代码时,出现了如下情况。
struct ip{
unsigned char version:4; // 版本
unsigned char hlen:4; // 首部长度
unsigned char tos; // 服务类型
unsigned short len; // 总长度
unsigned short id; // 标识符
unsigned short offset; // 标志和片偏移
unsigned char ttl; // 生存时间
unsigned char protocol; // 协议
unsigned short checksum; // 校验和
struct in_addr ipsrc; // 32位源ip地址
struct in_addr ipdst; // 32位目的ip地址
};
因为ip包头的版本字段和首部长度字段各自只占一个字节中的四个bit位,所以这里使用了位域的写法。
下面给出一个位域使用的例子,看了这个例子应该就理解位域的使用了。
#include <stdio.h>
#include <stdlib.h>
int main()
{
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
}bit,*pbit;
bit.a=1;
bit.b=7;
bit.c=15;
printf("%d,%d,%d\n",bit.a,bit.b,bit.c); //输出:1,7,15
pbit=&bit;
pbit->a=0;
pbit->b&=3;
pbit->c|=1;
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c ); //输出:0,3,15
}
程序的6,7,8三行分别给三个位域赋值
应注意赋值不能超过该位域的允许范围,超过时,仅将等号右侧值的低位赋值给位域)
比如说这个例子中,位域a只占一个bit位的大小,所以只能正确赋值整形的0和1,如果赋值更大的数字,发生截断。之后的打印整形不再正确。如将a赋值为2,那么编译器warning
test.c:12:10: warning: implicit truncation from 'int' to bitfield changes value
from 2 to 0 [-Wbitfield-constant-conversion]
bit.a=2;
^~
1 warning generated.
之后打印结果为a,发现结果为0,因为二进制位发生了截断。
同理b只有三位,能容纳的最大数字是7。