一、结构体大小的求取
结构体字节大小的计算需要满足字节对齐原则。
64位操作系统默认8字节对齐,32位操作系统默认4字节对齐
字节对齐原则
1.结构体成员变量的自身对齐量=本身的数据类型大小>操作系统默认对齐量?操作系统默认对齐量:本身的数据类型大小
2.结构体中每一个成员变量的起始位置,都在其自身对齐量的整数倍上(0除外)
3.结构体的整体大小是最大成员变量对齐量的整数倍
示例:
1.无嵌套结构体无数组
struct data
{
char t1; //t1的自身对齐量是1,偏移地址0是其整数倍,故直接存储1字节
char t2; //t2的自身对齐量是1,偏移地址1是其整数倍,故直接存储1字节
unsigned short t3;//t3的自身对齐量是2,偏移地址2是其整数倍,故直接存储2字节
unsigned long t4; //t4的自身对齐量是8,偏移地址4不是其整数倍,故需空四个偏移地址,再存储8字节
}; //共16个字节是最大对齐量8的倍数,故该结构体大小为16个字节
struct data
{
char t1; //t1的自身对齐量是1,偏移地址0是其整数倍,故直接存储1个字节
int t2; //t2的自身对齐量是4,偏移地址1不是其整数倍,故需空3个偏移地址,再存储4个字节
short t3;//t3的自身对齐量是2,偏移地址8是其整数倍,故直接存储2个字节
}; //总共10个字节不是最大对齐量4的整数倍,故需空2个偏移地址,则该结构体共12个字节
struct s1
{
char c1; //c1的自身对齐量是1,偏移地址0是其整数倍,故直接存储1个字节
int i; //i的自身对齐量是4,偏移地址1不是其整数倍,故需空3个偏移地址,再存储4个字节
char c2;//c2的自身对齐量是1,偏移地址8是其整数倍,故直接存储1个字节
};//总共9个字节不是最大对齐量4的整数倍,故需空3个偏移地址,则该结构体共12个字节
struct s2
{
char c1; //c1的自身对齐量是1,偏移地址0是其整数倍,故直接存储1个字节
char c2; //c2的自身对齐量是1,偏移地址1是其整数倍,故直接存储1个字节
int i; //i的自身对齐量是4,偏移地址2不是其整数倍,故需空2个偏移地址,再存储4个字节
}; //总共8个字节是最大对齐量4的整数倍,故该结构体共8个字节
typedef struct
{
int b;//b的自身对齐量是4,偏移地址0是其整数倍,故直接存储4个字节
char a;//a的自身对齐量是1,偏移地址4是其整数倍,故直接存储1个字节
long e;//e的自身对齐量是8,偏移地址5不是其整数倍,故需空3个偏移地址,再存储8个字节
char c;//c的自身对齐量是1,偏移地址16是其整数倍,故直接存储1个字节
float d;//d的自身对齐量是4,偏移地址17不是其整数倍,故需空3个偏移地址,再存储4个字节
double t;//t的自身对齐量是8,偏移地址24是其整数倍,故直接存储8个字节
}node;//总共32个字节是最大对齐量8的整数倍,故该结构体共32个字节
2.无嵌套结构体有数组
struct C
{
char a;//a的自身对齐量是1,偏移地址0是其整数倍,故直接存储1个字节
char b[3];//b的自身对齐量是1,偏移地址1是其整数倍,故直接存储3个字节
char c; //c的自身对齐量是1,偏移地址4是其整数倍,故直接存储1个字节
}; //总共5个字节是最大对齐量1的整数倍,故该结构体共5个字节
3.有嵌套结构体变量无数组
每个结构体都是一个独立的单位,需要分开算。嵌套结构体变量的总字节数算出来后再算其自身对齐量。
typedef struct Test
{
short a;//a的自身对齐量是2,偏移地址0是其整数倍,故直接存储2个字节
struct//拿出来单独算其总字节数
{
int b;//b的自身对齐量是4,偏移地址0是其整数倍,故直接存储4个字节
double c;//c的自身对齐量是8,偏移地址4不是其整数倍,故需空4个偏移地址,再存储8个字节
char d;//d的自身对齐量是1,偏移地址16是其整数倍,故直接存储1个字节
}p;/*总共17个字节不是最大对齐量8的整数倍,故需空7个偏移地址,则该结构体共24个字节
p的自身对齐量是8,偏移地址2不是其整数倍,故需空6个偏移地址,再存储24个字节*/
int e;//b的自身对齐量是4,偏移地址32是其整数倍,故直接存储4个字节
}Test;//总共36个字节不是最大对齐量8的整数倍,故需空4个偏移地址,则该结构体共40个字节
4.有嵌套结构体变量有数组
typedef struct Test
{
short a;//a的自身对齐量是2,偏移地址0是其整数倍,故直接存储2个字节
struct//拿出来单独算其总字节数
{
int b;//a的自身对齐量是4,偏移地址0是其整数倍,故直接存储4个字节
double c[10];//c的自身对齐量是8,偏移地址4不是其整数倍,故需空4个偏移地址,再存储80个字节
char d;//d的自身对齐量是1,偏移地址88是其整数倍,故直接存储1个字节
}p;/*总共89个字节不是最大对齐量8的整数倍,故需空7个偏移地址,则该结构体共96个字节
p的自身对齐量是8,偏移地址2不是其整数倍,故需空6个偏移地址,再存储96个字节*/
int e;//e的自身对齐量是4,偏移地址104是其整数倍,故直接存储4个字节
}Test;//总共108个字节不是最大对齐量8的整数倍,故需空4个偏移地址,则该结构体共112个字节
二、验证大小端存储
1.强制转换数据类型验证
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int a=0x12345678;
char b=(char)a;
if(b==0x78)
{
printf("小端存储\n");
}
else if(b==0x12)
{
printf("大端存储\n");
}
return 0;
}
2.指针验证
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int a=0x12345678;
char* p=&a;
if(*p==0x78)
{
printf("小端存储\n");
}
else if(*p==0x12)
{
printf("大端存储\n");
}
return 0;
}
出现警告是因为指针的数据类型和变量的数据类型不一致,会发生强制转换,按指针的数据类型字节大小取地址。
故指针的数据类型一般要和变量保持一致
3.共同体验证
共用体中的所有成员,共用同一片内存。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef union
{
int a;
char b;
}A;
int main(int argc, const char *argv[])
{
A P;
P.a=0x12345678;
if(P.b==0x78)
{
printf("小端存储\n");
}
else if(P.b==0x12)
{
printf("大端存储\n");
}
return 0;
}
三、枚举
枚举有和结构体相同的地方,故可以将其类似于结构体进行记忆。但枚举也有和结构体明显不同的地方,故不能简单的用结构体的知识去认知。
枚举和结构体的声明基本一致,不同之处在于枚举的成员是一个整型常量,每个成员之间需要用逗号(,)隔开,且最后一个成员可以省略逗号;结构体的成员是一个需要加上数据类型的变量,每个成员之间需要用分号(;)隔开,且最后一个成员不可以省略分号。
枚举和结构体的变量定义完全一致