#include <stdio.h>
struct S1
{
char c1;//1字节
int i;//4字节
char c2;//1字节
};
struct S2
{
char c1;//1字节
char c2;//1字节
int i;//4字节
};
int main()
{
struct S1 s;
struct S2 s2;
printf("%d\n",sizeof(s)):
printf("%d\n",sizeof(s2)):
//结果s的大小为12,s2的大小为8
}
struct S3
{
double d;
char c;
int i;
};//16
struct S4
{
char c1;//1
struct S3 s3;//16
double d;//8
};
结构体内存对齐
结构体第一个成员放置在偏移量为0的地址处。
其他数字要对齐到对齐数的整数倍地址处,对齐数=编译器默认的一个对齐数与该成员大小的较小值。vs中对齐数默认为8,linux环境下没有默认对齐数。就是看8和成员类型的大小,对齐到较小的数的整数倍。
最后结构体的大小要为最大成员类型的整数倍。
12就是这么来的。
同理s2
如果在设计结构体的时候既想节省空间,又满足对齐,可以把占用空间小的成员放置在一起。
offsetof - 宏
包含在头文件<stddef.h>中。
计算结构体成员相对于起始位置的偏移量的。
int main()
{
printf("%u\n", offsetof(struct S3, d));
printf("%u\n", offsetof(struct S3, c));
printf("%u\n", offsetof(struct S3, i));
}
修改默认对齐数
#pragma pack(1)
struct S
{
char c;//1
double d;//8
};
#pragma pack()
int main()
{
struct S s;
printf("%d\n", sizeof(s));
return 0;
}
使用以下代码:
#pragma pack()
来修改默认对齐数,括号内写想设置的默认对齐数。
位段
位段的声明和结构很相似,但是有区别。
1.位段成员必须是int ,unsigned int 或者signed int。
2.位段的成员后面还有一个冒号和一个数字。
struct A
{
char a : 3 ; //2代表_a这个成员所占内存比特位。
char b : 4 ;
char c : 5;
char d : 4;
};
int main()
{
struct S s = {0};
printf("%d",sizeof(A)); //结果只占三个字节。
s.a=10;
s.b=12;
s.c=3;
s.d=4;
return 0;
}
位段的跨平台问题:
1.int位段被当成有符号还是无符号数不确定。
2.位段中最大位数目不确定(16位机器最大16,32位最大32)
3.位段中成员在内存中从左向右分配还是从右向左分配未定义。
4.当一个结构保护你两个位段,第二个位段成员较大,无法容纳于第一个位段剩余的位时,是继续用空比特位还是舍弃空比特位不确定。
枚举
enum Color
{
RED, //默认初始化成0,往下递增,
GREEN, // 因此这里就是1。
BLUE
};
enum Color
{
RED=5, //这样的话往下递增,Green就是6。
GREEN,
BLUE
};
//#define RED 5
//define也可以定义常量,枚举更具有代码可读性,有类型检查,更加严谨。防止了命名污染等等。
int main()
{
enum Color d = RED; //RED尽量不要写成5,避免编译器类型检查。
//RED=6; 这么写是错误的。
printf("%d\n", RED);
return 0;
}
联合(共用体)
也是一种特殊的自用体。
union Un
{
char c;//1
int i;//4
};
int main()
{
union Un u;
u.c = 0x55;
u.i = 0;
printf("%d\n", sizeof(u)); //结果为4。
printf("%p\n", &u);
printf("%p\n", &(u.c));
printf("%p\n", &(u.i)); //三个地址相同。因为i和c有一处字节共用。因此改一处都会改。
return 0;
}
用联合来判断大小端:
int check_sys()
{
union Un
{
char c;
int i;
}u;
u.i = 1;
return u.c;//
}
int main()
{
if (1 == check_sys())
{
printf("小端\n");
}
else
{
printf("大端\n");
}
//原判断方法。
//int i = 1;
//01 00 00 00
/*if (1 == *(char*)&i)
{
printf("小端\n");
}
else
{
printf("大端\n");
}*/
return 0;
}
联合体大小计算:
union Un
{
char arr[5];//5
int i;//4
};
int main()
{
printf("%d\n", sizeof(union Un)); //结果为8。
//联合体大小不一定是最大成员大小,可能会存在空内存来补齐最大对齐数整数倍。
return 0;
}