一、首先说概念:
位结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构比按位运算符更加方便。
位结构定义的一般形式为:
} 位结构变量;
变量名是选择项, 可以不命名, 这样规定是为了排列需要。
例如: 下面定义了一个位结构。
struct webpage{ unsigned char incon: 8; unsigned char txcolor: 4; unsigned char bgcolor: 3; unsigned char blink: 1; }ch; printf("%d\n",sizeof(struct webpage));输出:2。
例如:
struct info{ char name[8]; int age; struct addr address; float pay; unsigned char state: 1; unsigned char pay: 1; }workers;
#include "stdio.h" void main() { union { struct student { unsigned char s1:1; unsigned char s2:3; }x; unsigned char c; }v; v.c=0; v.x.s1=0; v.x.s2=4; printf("%d\n",v.c); printf("%d\n",sizeof(v.x)); }输出:
即结构体成员申请是按照顺序从低地址开始。所以上边结构体v在内存中数据的排列顺序为
s1 s2
|0| 0|0|1| 0|0|0|0| (1个字节,因为是unsigned char类型)
低地址 高地址
s1放着0
s2放着4(二进制100),在内存里由低到高为“|0|0|1|”。
所以v.c为二进制00001000,即十进制8。
同时,因为s1占一个位,s2占三个位,而两者都是unsigned char型,且最大的数据类型也就是unsigned char型,一个字节足够放下s1和s2了。所以我们看到struct student的大小为1个字节。
如果从先申请的放在高字节,则上边的输出为
s2 s1
0000 |001 |0
即输出应该是:
64
1
三、位结构的位对齐问题
位结构的其实不存在位对齐问题,即位不需要对齐。其他方面,位结构和一般结构体类似,遵循结构体的对齐原则,
#include "stdio.h" void main() { union { struct student { unsigned char s1:1; unsigned char s2:2; unsigned char s3:2; }x; unsigned char c; }v; v.c=0; v.x.s1=0; v.x.s3=2; printf("%d\n",v.c); printf("%d\n",sizeof(v.x)); }
因为它只按整体对齐,所以为
s1s2s3
0 0001000
即二进制00010000等于十进制16,而不是
s1s2 s3
0 00 0 01 00
再举一个位结构体的例子
#include "stdio.h" void main() { union { struct student { unsigned char s1:1; unsigned char s2:2; unsigned short s3:2; }x; unsigned short c; unsigned int d; }v; v.d=0; v.x.s1=0; v.x.s3=2; printf("%d\n",v.d); printf("%d\n",sizeof(v.x)); }
131072=(10 00000000 00000000)b
因为遵循结构体对齐原则,s3跳过了2个字节。
s1s2 s3
0 00 00000| 00000000| 01
碰到个面试题:
设计个结构用两个字节表示2010/10/11-2110/10/11之间的任意日期
#include <stdio.h> #define YEAR(y) ((y)-2010) struct DATA { unsigned short year:7; unsigned short month:4; unsigned short day:5; }; int main() { DATA data; data.year = YEAR(2110); data.month = 12; data.day = 31; printf("%d\n",sizeof(DATA)); printf("%d/%d/%d",2010+data.year,data.month,data.day); return 0; }