【C语言进阶剖析】10、struct 和 union 分析

1 struct 的小秘密

C 语言中的 struct 可以看作变量的集合

1.1 空结构体大小

struct 的问题:空结构体占多大内存?
对于这个问题,有两种不同的思路:第一,空结构体大小为0,第二,空结构体本来就是为了操作变量的集合,为空没有意义,因该编译不通过。

下面用 gcc 编译器编译,看一下运行结果

#include<stdio.h>
struct TS{

};
int main(){
    struct TS t1;
    struct TS t2;
    printf("%ld\n", sizeof(struct TS));
    printf("sizeof(t1) = %ld, &t1 = %p\n", sizeof(t1), &t1);
    printf("sizeof(t2) = %ld, &t2 = %p\n", sizeof(t2), &t2);
    return 0;
}

在这里插入图片描述

对于 gcc 编译器,将空结构体的大小视为 0

对于空结构体的处理,上面的两种想法都正确,这是 C 语言中的一个灰色地带,既可以认为空结构体大小为 0,也可以认为结构体的存在就是为了组成一个变量的集合,空结构体没有意思,不合法。对于 gcc 编译器来说,认为空结构体大小为 0,对于 BCC 编译器,直接报错,不能编译空结构体。

1.2 结构体与柔性数组

  • 柔性数组即数组大小待定的数组
  • C 语言中可以由结构体产生柔性数组
  • C 语言中的结构体的最后一个元素可以是大小未知的数组

柔性数组定义如下:

struct SoftArray{
    int len;
    int array[];
};

那么问题来了,结构体中最后一个元素是数组,该数组大小是未知的,这个结构体大小是多少呢?

#include<stdio.h>
struct SoftArray{
    int len;
    int array[];
};
int main(){
    printf("%ld\n", sizeof(struct SoftArray));
    return 0;
}

运行结果如下:
在这里插入图片描述

结果解说:SoftArray 中 array 仅是一个待使用的标识符,不占用存储空间。结构体的大小就是 len 的大小,为 4 个字节。

柔性数组的用法如下:

struct SoftArray{
    int len;
    int array[];
};
struct SoftArray* sa = NULL;
sa = (struct SoftArray*) malloc(sizeof(struct SoftArray) + sizeof(int)*5);
sa->len = 5;

malloc 申请空间时,不仅要申请结构体 SoftArray 的空间,还要申请数组 array 的空间,并将 len 的大小赋值为 array 数组的大小。
在这里插入图片描述
下面通过一个实例来说明动态数组的使用。

// 10-2.c
#include <stdio.h>
#include <malloc.h>
struct SoftArray {
    int len;
    int array[];
};
struct SoftArray* create_soft_array(int size) {
    struct SoftArray* ret = NULL;
    if( size > 0 ) {
        ret = (struct SoftArray*)malloc(sizeof(struct SoftArray) + sizeof(int) * size);
        ret->len = size;
    }
    return ret;
}
void delete_soft_array(struct SoftArray* sa) {
    free(sa);
}
void func(struct SoftArray* sa) {
    int i = 0;
    if( NULL != sa ) {
        for(i=0; i<sa->len; i++) {
            sa->array[i] = i + 1;
        }
    } 
}
int main() {
    int i = 0;
    struct SoftArray* sa = create_soft_array(10);
    func(sa);
    for(i=0; i<sa->len; i++) {
        printf("%d\n", sa->array[i]);
    }
    delete_soft_array(sa);
    return 0;
}

在这里插入图片描述
看了动态数组的用法,那么动态数组到底有什么用呢?定义一个数组时,我们就要定义数组的大小,但是如果使用柔性数组,可以在时候的时候再指定数组的大小,动态分配内存。

2 C 语言中的union

C 语言中的 union 在语法上与 struct 相似,union 只分配最大成员的空间,所有成员共享这个空间。
在这里插入图片描述

对于 struct,每一个变量都占用空间,所以三个 int 成员,大小为 12 字节,union 中三个变量都是 int,最大也当然是 int,所以该 union 大小为 4。

这里需要注意一个问题,union 的使用受系统大小端的影响

大端模式:高地址存储低位数据,低地址存储高位数据
小端模式:高地址存储高位数据,低地址存储低位数据

在这里插入图片描述
那么问题来了,对于如下程序,会输出什么呢?
在这里插入图片描述

联合体将占用 4 个字节的存储空间,char c 的值将受大小端模式的影响,c 的值取低地址空间 1 字节内存中的值,在小端模式中,c 的值为 1,在大端模式中 c 的值为 0。
注意:char c 始终从低地址空间取数据。

下面通过一个实验,判断系统的是大端模式,还是小端模式

//10-3.c
#include<stdio.h>
int system_mode(){
    union SM{
        int i;
        char c;
    };
    union SM sm;
    sm.i = 1;
    return sm.c;
}
int main(){
    printf("system Mode: %d\n", system_mode());
    return 0;
}

在这里插入图片描述
打印结果为了,说明低地址空间为1,系统为小端模式。

3 小结

1、struct 中每个数据成员有独立的存储空间
2、struct 可以通过最后的数组标识符产生柔性数组
3、union 中的所有数据成员共享同一个存储空间
4、union 的使用受到系统大小端的影响

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值