网站建设与维护教学视频教程,seo关键词是什么意思,wordpress 留言功能,网站建设数据安全的意义c中的对齐问题
需要对齐的原因
尽管内存是以字节为单位#xff0c;但是大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存#xff0c;我们将上述这些存取单位称为内存存取粒度.
现在考虑4字节存取粒度的处理器取in…c中的对齐问题
需要对齐的原因
尽管内存是以字节为单位但是大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存我们将上述这些存取单位称为内存存取粒度.
现在考虑4字节存取粒度的处理器取int类型变量32位系统该处理器只能从地址为4的倍数的内存开始读取数据。
假如没有内存对齐机制数据可以任意存放现在一个int变量存放在从地址1开始的联系四个字节地址中该处理器去取数据时要先从0地址开始读取第一个4字节块,剔除不想要的字节0地址,然后从地址4开始读取下一个4字节块,同样剔除不要的数据567地址,最后留下的两块数据合并放入寄存器.这需要做很多工作. 对齐的规则
有效对齐值是 #pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。
注意 #pragma pack(n)中的n可以取(1 , 2 , 4 , 8 , 16)中的任意一值。
2规则 结构体变量的首地址是有效对齐值对齐单位的整数倍。 结构体第一个成员的偏移量offset为0以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍如有需要编译器会在成员之间加上填充字节。 结构体的总大小为有效对齐值的整数倍如有需要编译器会在最末一个成员之后加上填充字节。 结构体内类型相同的连续元素将在连续的空间内和数组一样。
运用上面的规则下面通过实际的例子进行计算。
例1
#include iostreamstruct MyStruct {char c;int i;short s;
};int main()
{MyStruct obj;std::cout start addr of obj (void*)obj std::endl;std::cout offset of c offsetof(MyStruct,c) std::endl;std::cout offset of i offsetof(MyStruct,i) std::endl;std::cout offset of s offsetof(MyStruct,s) std::endl;std::cout sizeof MyStruct sizeof(MyStruct);
}执行结果如下
start of obj 0x7fff2e8d1e94
offset of c 0
offset of i 4
offset of s 8
sizeof MyStruct 12结构中最长的数据类型是int长度也为4。因此结构体的有效对齐值是4。
对于c变量而言没有悬念将排在0偏移地址处。
对于变量i类型为int长度为4int和有效对齐值的最小值为4因此i需要排布在4的整数倍上因此第一个符合要求的偏移量就是4。
对于变量s类型为short长度为2short和有效对齐值二者中的最小值为2第一个符合要求的地址为8。
到目前为止使用的空间大小是10而结构体大小需要满足有效对齐值的整数倍因此需要2个填充因此结构体最终大小是12。 例2
#include iostream
#pragma pack(2)
struct MyStruct {char c;int i;short s;
};int main()
{MyStruct obj;std::cout start addr of obj (void*)obj std::endl;std::cout offset of c offsetof(MyStruct,c) std::endl;std::cout offset of i offsetof(MyStruct,i) std::endl;std::cout offset of s offsetof(MyStruct,s) std::endl;std::cout sizeof MyStruct sizeof(MyStruct);
}执行结果如下
start addr of obj 0x7fff488e3418
offset of c 0
offset of i 2
offset of s 6
sizeof MyStruct 8首先#pragma pack设置的对齐值是2结构中最长的数据类型是int长度也为4。因此结构体的有效对齐值是2。
对于c变量而言没有悬念将排在0偏移地址处。
对于变量i类型为int长度为4int和有效对齐值的最小值为2因此i需要排布在2的整数倍上因此第一个符合要求的偏移量就是2。
对于变量s类型为short长度为2short和有效对齐值二者中的最小值为2第一个符合要求的地址为6。
到目前为止使用的空间大小是8已经满足结构体大小是有效对齐值的整数倍的要求。 #include iostream
#pragma pack(1)
struct MyStruct {char c;int i;short s;
};int main()
{MyStruct obj;std::cout start addr of obj (void*)obj std::endl;std::cout offset of c offsetof(MyStruct,c) std::endl;std::cout offset of i offsetof(MyStruct,i) std::endl;std::cout offset of s offsetof(MyStruct,s) std::endl;std::cout sizeof MyStruct sizeof(MyStruct);
}执行结果如下
start addr of obj 0x7ffe96c067a9
offset of c 0
offset of i 1
offset of s 5
sizeof MyStruct 7首先#pragma pack设置的对齐值是1结构中最长的数据类型是int长度也为4。因此结构体的有效对齐值是1。
对于c变量而言没有悬念将排在0偏移地址处。
对于变量i类型为int长度为4int和有效对齐值的最小值为因此i需要排布在2的整数倍上因此第一个符合要求的偏移量就是1。
对于变量s类型为short长度为2short和有效对齐值二者中的最小值为2第一个符合要求的地址为5。
到目前为止使用的空间大小是7已经满足结构体大小是有效对齐值的整数倍的要求。 例4
#include iostream
#include emmintrin.hstruct MyStruct {char c;__m128i i;
};int main()
{MyStruct obj;std::cout start addr of obj (void*)obj std::endl;std::cout offset of c offsetof(MyStruct,c) std::endl;std::cout offset of i offsetof(MyStruct,i) std::endl;std::cout sizeof MyStruct sizeof(MyStruct);
}执行结果如下
start addr of obj 0x7fff9d47cd90
offset of c 0
offset of i 16
sizeof MyStruct 32首先结构中最长的数据类型是__m128i长度为16。因此结构体的有效对齐值是16。
对于c变量而言没有悬念将排在0偏移地址处。
对于变量i类型为__m128i长度为16__m128i和有效对齐值的最小值为16因此i需要排布在2的整数倍上因此第一个符合要求的偏移量就是16。 例5
#include iostream
#include emmintrin.h#pragma pack(8)
struct MyStruct {char c;__m128i i;
};int main()
{MyStruct obj;std::cout start addr of obj (void*)obj std::endl;std::cout offset of c offsetof(MyStruct,c) std::endl;std::cout offset of i offsetof(MyStruct,i) std::endl;std::cout sizeof MyStruct sizeof(MyStruct);
}执行结果如下
start addr of obj 0x7ffddbec2c40
offset of c 0
offset of i 8
sizeof MyStruct 24首先#pragma pack设置的对齐值是8结构中最长的数据类型是__m128i长度为16。因此结构体的有效对齐值是8。
对于c变量而言没有悬念将排在0偏移地址处。
对于变量i类型为__m128i长度为16__m128i和有效对齐值的最小值为8因此i需要排布在2的整数倍上因此第一个符合要求的偏移量就是8。 总结
为了高效的访问内存数据通常需要对内存数据进行对齐。#pragma pack(n)用于设置的对齐有效值如果设置比结构体的最长成员还大的对齐值将是无效的。