一、字节序
bool am_little_endian ()
{
unsigned short i=1;
return (int)*((char *)(&i)) ? true : false;
}
int main()
{
if(am_little_endian())
{
printf("本机字节序为小段序!\n");
}else
{
printf("本机字节序为大段序!\n");
}
return 0;
}
二、字节对齐
VS默认8,Linux默认4。
结构体字节对齐规则
先介绍三个概念:自身对齐值、指定对齐值、有效对齐值。
a: 自身对齐值:数据类型本身的对齐值,例如char类型的自身对齐值是1,short类型是2;
b: 指定对齐值:编译器或程序员指定的对齐值,32位单片机的指定对齐值默认是4;
c: 有效对齐值:自身对齐值和指定对齐值较小 的那个。
自定义类型的自身对齐值:自定义类型中对齐值最大的值
对齐有两个规则:
d: 不但结构体的成员有有效对齐值,结构体本身也有对齐值,这主要是考虑结构体的数组,对于结构体或者类,要将其补齐为其有效对齐值的整数倍。结构体的有效对齐值是其最大数据成员的自身对齐值;
e: 存放成员的起始地址必须是该成员有效对齐值的整数倍。
例子一:
#pragma pack (2)
typedef struct head {
char f
} _head;
#pragma pack ()
int a = sizeof(_head);//a = 1
假如结构体起始地址是0x0000,
成员f的自身对齐值1,指定对齐值2,所以有效对齐值是1,根据规则e地址0x0000是1的整数倍,故a存放起始地址是0x0000,占一个字节;
根据规则d,体结构体本身也有对齐值,是其最大数据成员的自身对齐值。所以这里是成员f,体结构体本身对齐值是1。再根据e,1是1的整数倍,所以结构体大小为1。
例子二:
#pragma pack (2)
typedef struct head {
char f //1+1
int b; //4
char c;//1+1
} _head;//1+1 + 4 + 1+1 = 8
#pragma pack ()
int a = sizeof(_head);//a = 8
假如结构体起始地址是0x0000
成员f的自身对齐值1,指定对齐值2,所以有效对齐值是1,根据规则e,地址0x0000是1的整数倍,故a存放起始地址是0x0000,占一个字节;
成员b的自身对齐值4,指定对齐值2,所以有效对齐值是2,根据规则e,地址0x0002是2的整数倍,故a存放起始地址是0x0002,占4个字节;
成员c的自身对齐值1,指定对齐值2,所以有效对齐值是1,根据规则e,地址0x0006是1的整数倍,故a存放起始地址是0x0006,占一个字节;
此时共用了7个字节,但是根据规则d,体结构体本身也有对齐值,是其最大数据成员的自身对齐值。所以这里是成员b,体结构体本身对齐值是4。再根据e,7不是4的整数倍,所以要+1,,即为8。
例子三:
#pragma pack (16)
typedef struct head {
char f //1+3
int b;//4
char e;//1+3
} _head;//all = 12
#pragma pack ()
_head h;
int a = sizeof(h); //a = 12
假如结构体起始地址是0x0000
成员f的自身对齐值1,指定对齐值16,所以有效对齐值是1,根据 规则e 地址0x0000是1的整数倍,故a存放起始地址是0x0000,占一个字节;
成员b的自身对齐值4,指定对齐值16,所以有效对齐值是4,规则e 地址0x0004是4的整数倍,故a存放起始地址是0x0004,占4个字节;
成员c的自身对齐值1,指定对齐值16,所以有效对齐值是1,规则e 地址0x0008是1的整数倍,故a存放起始地址是0x0008,占一个字节;
此时共用了9个字节,但是根据规则d,体结构体本身也有对齐值,是其最大数据成员的自身对齐值。所以这里是成员b,体结构体本身对齐值是4。再根据e,9不是4的整数倍,所以要+3,,即为12。
例子四:
#pragma pack (8)
typedef struct Test
{
short a; //2 +6
struct Inner
{
int b; //4 +4
double c; //8
long d; //4 +4
};
int e; //4 +4
}Test;
void main()
{
printf("%d\n", sizeof(Test)); //40
}
struct Inner 有效对齐字节是8
#pragma pack (8)
typedef struct Test
{
short a;//2 + 6
struct
{
int b;//4 +4
double c[10];//80
char d;//1+7
};
int e;//4
}Test; // sizeof == 112
同样int b不能按80对齐,而是按照double 本身的字节大小8对齐
double c[10];//80 有效字节数是8
#pragma pack (8)
struct S1
{
char a;//1+7
double b;//8
int c;//4+4
};//24
struct S2
{
char a;//1+3
int c;//4
double b;//8
};//16
有枚举的
#pragma pack (8)
union Un1
{
short c[6];
double i;
};
union Un2
{
short c[6];
int i;
};
struct S1
{
char c;//1+7
Un1 r1;//16
};
struct S2
{
char c;//1+3
Un2 r2;//12
};
枚举共享内存,所以是内存是最大的那个,Un1是short c[7];Un2是short c[6];,
Un1中最大成员字节是double ,是8,所以Un1字节是12+4 = 16
Un12中最大成员字节是int,是8,所以Un2字节是12
Un1 最大对齐是double也就是8,所以S1字节是1+7+16 = 24
Un2 最大对齐是double也就是4,S2字节是1+3+16 = 16
本文主要介绍了C++中的字节序和字节对齐知识。阐述了VS和Linux的默认对齐值,介绍了自身对齐值、指定对齐值、有效对齐值等概念及结构体字节对齐规则,并通过多个例子详细说明。还提及了枚举的内存共享情况,最后给出相关练习链接。

被折叠的 条评论
为什么被折叠?



