C语言中结构体struct与联合体union

发布时间 2023-11-09 17:07:25作者: ImreW

struct(结构体)与union(联合体)是C语言中两种不同的数据结构,两者都是常见的复合数据类型

定义

结构体(struct)

在C语言中,结构体(struct)指的是一种数据结构,是C语言中复合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。

结构体的定义如下所示,struct为结构体关键字tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量

struct tag
{
    member-list 
}variable-list; 

在一般情况下,tag、member-list、variable-list这3部分至少要出现2个。以下为示例:

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct 
{
    int a;
    char b;
    double c;
} s1;

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;

//也可以用typedef创建新类型
typedef struct
{
    int a;
    char b;
    double c; 
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;

结构体成员依据结构体变量类型的不同,一般有2种访问方式,一种为直接访问,一种为间接访问

  • 直接访问应用于普通的结构体变量。直接访问使用 结构体变量名.成员名
  • 间接访问应用于指向结构体变量的指针。间接访问使用 (*结构体指针名).成员名 或者使用 结构体指针名->成员名。相同的成员名称依靠不同的变量前缀区分。
struct SIMPLE
{
    int a;
    char b;
};

//声明结构体变量s1和指向结构体变量的指针s2
struct SIMPLE s1, *s2;

//给变量s1和s2的成员赋值,注意s1.a和s2->a并不是同一成员
s1.a = 5;
s1.b = 6;
s2->a = 3;
s2->b = 4;

联合体(union)

在计算机科学中,联合体(英语:union)又名共用体,是一种具有多个类型或格式的值,或者把它定义为一种由具有这样的值的变量形成的数据结构。一些编程语言可以支持被称为“联合体”的特殊的资料类型,来表示上述的变量。与枚举和结构体不同的是,一个联合体的长度等于其内部长度最大的成员的长度,并且它们都共享着同一段内存

在C语言中,一个典型的例子如下:

union name1
{
   int     a;
   float   b;
   char    c;
} uvar;

区别

结构体

struct MyStruct
{
    double a;
    int b;
    char c;
};
struct MyStruct value;

联合体

union MyUnion
{
    double a;
    int b;
    char c;
};
union MyUnion value;

变量value内存空间占用情况:

一、内存占用

结构体(struct)和联合体(union)都是由不同的数据类型成员组成的,但是结构体所有成员占用的内存空间累加的,而联合体(union)中所有的成员公用一块地址空间。

  • 结构体(struct)中的内存空间等于所有成员长度之联合体(union)成员不能同时占用内存空间,长度等于最长成员的长度
  • 结构体:空间包容性强,但是内存空间必须全部分配
  • 联合体:成员是互斥的,但是可以大大节省内存空间
typedef union {double i; int k[5]; char c;}DATE;
typedef struct data( int cat; DATE cow;double dog;)too;
DATE max;
printf ("%d", sizeof(too)+sizeof(max));

假设为32位机器,int型占4个字节, double型占8个字节,char型占1个字节,而DATE是一个联合型变量,联合型变量共用空间,uion里面最大的变量类型是int[5],所以占用20个字节,它的大小是20,而由于 union中double占了8个字节,因此 union是要8个字节对齐,所占内存空间为8的倍数为了实现8个字节对齐,所占空间为24.而data是一个结构体变量,每个变量分开占用空间,依次为 sizeof(int)+ sizeof(DATE)+ sizeof( double)=4+24+8=36按照8字节对齐,占用空间为40,所以结果为40+24=64。

二、成员互斥

在实际应用中我们一般都使用结构体来定义数据组合而成的结构型变量,而在各数据类型各变量占用空间差不多并且对各变量同时使用要求不高的场合(单从内存使用上)也可以灵活的使用union。

应用

1、变量的初始化

在初始化的时候,只应对一个成员进行初始化即在初始化列表中只有一个初始值。原因就是联合体的所有成员共用一个首地址,在默认情况下,会将这个初始值初始化给联合体变量的第一个成员

union MyUnion
{
    double a;
    int b;
    char c;
};
//为第一个成员初始化
union MyUnion un1 = {5.0f};

//错误初始化,不能为多个成员初始化
union MyUnion un1 = {5.0f, 10};

//对其它位置的成员进行初始化,则可以通过指定初始化方式
union MyUnion un1 = {.b = 10};

//与结构体一样,也可以将一个联合体变量作为初始值,直接初始化给同类型的另一个联合体变量
union MyUnion un2 = un1;

2、数据位操作

#include<stdio.h>
typedef struct
{
  unsigned char bit0:1;
  unsigned char bit1:1;
  unsigned char bit2:1;
  unsigned char bit3:1;
  unsigned char bit4:1;
  unsigned char bit5:1;
  unsigned char bit6:1;
  unsigned char bit7:1;
}bitValue;

typedef union
{
  unsigned char bytedata;
  bitValue  bitdata;
}regValue;

int main()
{
  regValue data;

  data.bytedata= 0x5A;
  printf("%d",data.bitdata.bit5);  //读取第6位

  data.bitdata.bit7 = 1;           //修改第8位
  return 0;
}

可以看出,通过访问和修改联合体中的定义bitdata成员,可以间接的访问和修改定义的bytedata的值,这可以用在嵌入式的寄存器位操作上。