C++ 有没有办法防止组合类的填充
假设是64位机器: 如果我从a类开始:C++ 有没有办法防止组合类的填充,c++,padding,C++,Padding,假设是64位机器: 如果我从a类开始: struct A { int* a1; //8 int* a2; //8 uint16_t a3; //2 uint16_t a4; //2 uint32_t a5; //4 uint32_t a6; //4 uint32_t a7; //4 }; 现在所有单个成员都已正确对齐,A的大小为32字节,从a5到a1的偏移量为20字节 现在,如果我尝试如下重构: struct A_part1 {
struct A
{
int* a1; //8
int* a2; //8
uint16_t a3; //2
uint16_t a4; //2
uint32_t a5; //4
uint32_t a6; //4
uint32_t a7; //4
};
现在所有单个成员都已正确对齐,A
的大小为32字节,从a5
到a1
的偏移量为20字节
现在,如果我尝试如下重构:
struct A_part1
{
int* a1; //8
int* a2; //8
uint16_t a3; //2
uint16_t a4; //2
};
struct A_new
{
A_part1 a1;
uint32_t a5; //4
uint32_t a6; //4
uint32_t a7; //4
};
现在A_new
的大小是40个字节,因为A_part1
被填充到24个字节,而A_new
随后从36个字节填充到40个字节
可能编译器正在尝试确保相邻的部分1
对齐
如果我知道我只会在
A
中使用A\u part1
,在代码< > AXPARTHOR> <代码> >中,我必须选择的唯一选项是:<代码> AyNeX/<代码>将具有与原代码相同的特性> A< <代码> < /p> < p>您是正确的:标准C++中没有办法指定“代码<结构> <代码> s的填充布局,因此您会被编译器特定的代码所困扰。控制机制,如#pragma pack
如果我知道我只会在A中使用A_part1,这是我唯一的选择
必须在此处的零件1上使用pragma包,以确保新零件
是否具有与原A相同的特征
不可以。pragma不是指定布局和填充的唯一方法
在我曾经开发过的一个嵌入式软件中,我们找到了解决pragma问题的几种方法
< C和C++都没有提供内存布局语义。 但是一种很容易理解的技术,至少在逐字段的基础上,是显式地编码字节驻留在类或结构中的位置。通过重构和添加小字节移动方法,可以大大减少工作量 注意:七个字段很小,因此“容易”。五十块地太累了。一百个字段是“让我们写一些代码来写一些代码”。您的容忍度会有所不同 这种技术在需要的地方将字节显式地逐字节移动到类数据中。优点:1)无填充(除非您需要)。2) 对编译器选项更改不敏感。3) 便携式 小示例(编译,但未测试)(注意:任意endian选择,我们使用传统的endian转换)
A类
{
//int*a1;//8 0..7
//int*a2;//8..15
//uint16\u t a3;//2 16..17
//uint16_t a4;//2 18..19
//
//uint32\u t a5;//4等
//uint32\u t a6;//4
//uint32\u t a7;//4
// ...
//修改字段a3
无效a3(uint16_t val){
//如果需要,请更正目标端的val------vvv
数据[Oa3+0]=static_cast((val>>0)&0xff);//LSB
数据[Oa3+1]=静态_cast((val>>8)&0xff);//MSB
}
//访问字段a3
uint16_t a3(){
//如果需要,请更正尾数的val-----------------vvv
uint16_t val=static_cast((数据[Oa3+0]注意a)pragma通常不被认为是可移植的。2)不同的编译器可能具有类似的pragma,但它们的名称不一定相同。3)编译器选项(即优化级别)可能会改变与以前的设置相比的布局,并且您可能需要测试PrabMa仍然在做您想要的。另一方面,我在C++中用PrimaMeX的经验通常是这样的。@ Skimon有几种方法来指定内存结构/类的布局和填充。我没有评估编译选项更改时pragma的行为。下面我的回答是我在生产代码中使用的3种“标准C++”技术之一(即可移植和不带pragma)。
class A
{
// int* a1; //8 0..7
// int* a2; //8 8..15
// uint16_t a3; //2 16..17
// uint16_t a4; //2 18..19
//
// uint32_t a5; //4 etc
// uint32_t a6; //4
// uint32_t a7; //4
// ...
// modify field a3
void a3(uint16_t val) {
// if needed, correct val for destination endianess ------vvv
data[Oa3+0] = static_cast<uint8_t>((val >> 0) & 0xff); // LSB
data[Oa3+1] = static_cast<uint8_t>((val >> 8) & 0xff); // MSB
}
// access field a3
uint16_t a3() {
// if needed, correct val for endianess ---------------------vvv
uint16_t val = static_cast<uint16_t>((data[Oa3+0] << 0) + // LSB
(data[Oa3+8] << 8)); // MSB
return (val);
}
// continue for each field
private:
enum {
Oa1 = 0, // Offset a1
Oa2 = 8,
Oa3 = 16
//... etc
};
uint8_t data[(8+8+2+2+(3*4))];
};