C语言结构体和位段

结构体类型

如图,结构体的关键字是struct,stu是结构体的标签。没有标签的结构体就是匿名结构体,匿名结构体只能使用一次。

下面的name、age、height是结构体的成员。

struct stu 与int /float一样,是类型,可以用来创建变量。不一样的是,stu是自己定义的标签。而结构体声明以后,跟着的s1,s2是结构体的变量。

C语言结构体和位段_第1张图片

struct stu
{
   char name[];
   int age;
   float height;
}s1,s2;

int main()
{
  //...
   struct stu s1 = {"zhangsan",13,170.1};
   return 0;
}

除了上图显示的,还有另一种初始化方式。


  struct stu s2 ={.age = 17, .name = "lisi", .height = 190.2};

访问结构体变量的具体内容。结构体变量名 . 结构体成员名。

printf("%d\n",s1.age);
printf("%f\n",s2.height);
printf("%s\n",s1.name);

也可以通过指针访问。结构体指针 -> 结构体成员名。 

struct stu *p = &s1;
printf("%d\n", p->name);

结构体内存对齐

创建结构体也需要向内存申请空间。而不同的成员位置也会导致申请的空间大小有所变化,这是因为结构体内存需要对齐导致。

如下图所示,成员相同的结构体,申请的空间会不一样。

struct stu1
{
  int age;
  char name;
  char email;
};

struct stu2
{
  char name;
  int age;
  char email;
};

结构体对齐有4条规则:

1.结构体的第一个成员对齐到结构体变量偏移量为0的地址。

2.结构体的其他变量要对齐到对齐数的整数倍。

对齐数:变量自身的大小(如int是4个字节)与编译器默认对齐数(如vs是8)中,较小的那个数。(4<8,所以int创建的变量在vs平台下的对齐数就是4)

3.结构体总大小为最大对齐数的整数倍。(比如上面创建的结构体stu2,最大对齐数是4,所以结构体总大小就得是4的整数倍)

4.结构体有嵌套的情况下,嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍上,结构体总大小是内部所有成员中最大对齐数的整数倍。

C语言结构体和位段_第2张图片

虽然申请了8个字节,但其实两个字节没有被占用浪费掉了。后面的stu2也是这样。浪费了6个字节。

为什么要有对齐数?

1.有些编译器只能从特定的对齐数上取数,比如int型从4的对齐数取数,如果不采用对齐,那么取不到数。

2.编译器在读取内存的时候有些是8个字节8个字节的取,如果不采用对齐数,就可能出现一次读取没读到完整的字节,要读取好几次才能读取到一个变量。有了对齐数,一次就能读取到,运行速度提高很多。

采用对齐数,就是用空间的些许浪费换取时间。

结构体实现位段

位段声明

struct A
{
  int a : 2;
  int b : 4;
  int c : 30;
};

位段和结构体不同的有两点

1. 位段的成员只能是整型家族的,包括int 、 unsigned int 、 signed int 、char

2. 位段后面有个冒号还有个数,这个数的单位是比特,代表这个变量可以占用的内存大小。

那么,整个结构体A所占用的内存是多少呢?

2+4+30=36bite 

但实际上不只。

位段的内存申请不是按照比特申请的,是按照char和int的方式,也就是1个字节或者4个字节来申请的。

每个编译器分配内存的方式不一样。这是int型,先给32个bite,放不下了再申请4个字节。但是从左往右放还是从右往左放(从高地址往低地址放,还是从低地址往高地址放)都不确定的。以及,剩下的内存放不下了是先填满再放,还是直接把剩下的浪费掉,把数据存放在新申请的内存放。不同编译器都不太一样。这个要自己测试。

所以这个struct A在VS上占用8个字节。

位段使用虽然比较节省空间。但是不太方便跨平台。所以一般是在测试了解了编译器存放位段方式之后再使用的。

位段应用场景

位段可以用于网络协议ip数据报的形式,有些只需要传8个比特或4个比特,那么就可以用到位段,而不至于每种内型都申请4个字节(那样传输效率慢也占用空间)。

除此之外,还有许多其他运用场景。

你可能感兴趣的:(c语言,数据结构,开发语言)