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 的使用受到系统大小端的影响