东莞自助建站平台,网站标题flash,科技智库青年人才计划,app营销策划方案目录
1.结构体内存对齐
对偏移量的理解#xff1a;
2.结构体的大小计算
2.1结构体中只有普通的数据类型的大小计算
2.2 结构体中有嵌套的结构体的大小计算
3.修改默认对齐数
4.为什么存在内存对齐? 这篇文章主要介绍结构体内存对齐和如何计算大小。 在学习结构体内存… 目录
1.结构体内存对齐
对偏移量的理解
2.结构体的大小计算
2.1结构体中只有普通的数据类型的大小计算
2.2 结构体中有嵌套的结构体的大小计算
3.修改默认对齐数
4.为什么存在内存对齐? 这篇文章主要介绍结构体内存对齐和如何计算大小。 在学习结构体内存对齐之前不知道大家有没有注意到当我们有两个结构体它们的成员变量类型和个数相同只是顺序不同当计算它们的大小时它们的大小不相同例如下面的代码
#includestdio.h
struct S1
{char c1;int i;char c2;
};
struct S2
{int i;char c1;char c2;
};
int main()
{printf(%d\n, sizeof(struct S1));printf(%d\n, sizeof(struct S2));return 0;
}
sizeof计算的大小不相同 现在我们就来学习如何计算结构体的大小。 1.结构体内存对齐 结构体内存对齐Struct Memory Alignment是指编译器在分配结构体变量的内存空间时按照一定规则对结构体成员进行排列以保证结构体的访问效率和内存对齐要求。 在计算结构体的大小之前我们需要了解结构体的内存对齐规则
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处。 对齐数 编译器默认的一个对齐数与该成员大小的较小值。 VS中默认的值为8Linux中没有默认对齐数对齐数就是成员自身的大小
3. 结构体总大小为最大对齐数每个成员变量都有一个对齐数的整数倍。
4. 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。
对偏移量的理解 利用 offsetof 可以结算结构体成员变量相较于结构体起始位置的偏移量
#includestddef.h
#includestdio.h
struct S1
{char c1;int i;char c2;
};
int main()
{printf(%d\n, offsetof(struct S1, c1));printf(%d\n, offsetof(struct S1, i));printf(%d\n, offsetof(struct S1, c2));return 0;
} 根据每个成员变量的偏移量我们可以结算结构体成员变量在内存中的存储位置 根据上面的现象分析我们发现结构体成员不是在内存中连续存放的。
如果想要知道为什么会有浪费掉的空间我们还得根据结构体的对齐规则继续学习。 2.结构体的大小计算
下面讲解如何根据结构体内存对齐规则来计算结构体的大小
2.1结构体中只有普通的数据类型的大小计算
还是以这个结构体类型为例
struct S1
{char c1;int i;char c2;
}; 以同样的方法再来计算下面这个结构体的大小
struct S2
{int i;char c1;char c2;
}; 此时就已经解决了开头的疑问了。 为了巩固学习的知识再举出一个计算结构体大小的例子
struct S3
{double d;char c;int i;
}; 当结构体中含有数组时该怎么计算大小呢 当结构体中有数组类型的变量我们只需要将数组看作是多个相同类型的变量即可如下图所示 编译测试 2.2 结构体中有嵌套的结构体的大小计算
对于结构体中含有嵌套的结构体我们就需要使用第4条规则了 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整 体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。 计算一个试试
struct S
{double d1;char c1;int i;
};
struct S7
{char c2;struct S s;double d2;
};
int main()
{printf(%d\n, sizeof(struct S7));return 0;
} 3.修改默认对齐数
之前我们见过了 #pragma 这个预处理指令这里我们再次使用可以改变我们的默认对齐数。
#pragma pack(8)//设置默认对齐数为8
struct S1
{char c1;int i;char c2;
};
#pragma pack() //取消设置的默认对齐数还原为默认#pragma pack(1)//设置默认对齐数为1
struct S2
{char c1;int i;char c2;
};
#pragma pack()//取消设置的默认对齐数还原为默认int main()
{printf(%d\n, sizeof(struct S1));printf(%d\n, sizeof(struct S2));return 0;
}
输出结果 一般情况下对齐数都是设置成2的次方数不会随意设置成其他数 。 结论 结构在对齐方式不合适的时候我们可以自己更改默认对齐数。 4.为什么存在内存对齐? 大部分的参考资料都是如是说的 1. 平台原因(移植原因)
不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异常。
2. 性能原因
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访 问。
总体来说 结构体的内存对齐是拿空间来换取时间的做法
拓展 结构体内存对齐Struct Memory Alignment是指编译器在分配结构体变量的内存空间时按照一定规则对结构体成员进行排列以保证结构体的访问效率和内存对齐要求。 在计算机中访问内存的速度是有限的而且通常是按照特定的字节大小进行的。为了提高内存访问的效率许多计算机体系结构要求特定类型的数据在内存中的地址必须是某个特定值的倍数。这个特定值通常是数据类型的大小或者是处理器的字长。 结构体内存对齐的目的是为了满足这些对齐要求以减少内存访问的时间和成本。当结构体的成员变量按照对齐规则进行排列时可以保证每个成员变量的地址都是对齐的从而提高内存访问的效率。 具体的对齐规则可能因编译器、操作系统和处理器的不同而有所差异。通常情况下对齐规则会考虑数据类型的大小和对齐要求以及结构体成员的顺序和类型。编译器会在结构体的成员之间插入填充字节Padding Bytes以保证每个成员的地址满足对齐要求。 需要注意的是结构体内存对齐可能会导致结构体的大小增加因为填充字节会占用额外的内存空间。这种增加的大小可能会影响结构体的内存布局和内存占用特别是在涉及到结构体的嵌套、数组和文件IO等情况下。 在一些特殊情况下可以使用编译器提供的指令或者属性来控制结构体的内存对齐方式以满足特定的需求。 那在设计结构体的时候我们既要满足对齐又要节省空间如何做到 让占用空间小的成员尽量集中在一起。 struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};S1和S2类型的成员一模一样但是S1和S2所占空间的大小有了一些区别。