C语言结构体中内存对齐的问题理解

目录
  • 前言
  • 思考
  • 结构体在内存中开辟空间时内存对齐的规则
  • 为什么存在内存对齐
    • 1.平台的原因
    • 2.性能的原因

前言

学C的同学应该知道~

想精通C语言就不得不面对—指针与内存

续上次指针的进阶,这一章我来聊一聊C语言内存对齐的问题

学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的

思考

#include<stdio.h>
typedef struct s1
{
	char a;
	char b;
	int c;
}s1;
typedef struct s2
{
	char a;
	int c;
	char b;
}s2;
int main()
{

	//内存对齐的现象
	printf("%d\n", sizeof(s1));
	printf("%d\n", sizeof(s2));
	return 0;
}

很显然这一段代码就是计算s1与s2向系统申请的内存大小

我:两个char类型各为一,再加上应该int类型的四,结果就是六

诚挚的乔治:你说的对,但不完全对,在结构体中会出现内存对齐的现象,不信?看结果

别慌,看到文章的最后,你(也许)就会恍然大悟

在结构体中,内存不是成员的大小之和

结构体在内存中开辟空间时内存对齐的规则

1.结构体中的第一个成员存放在这个结构体的零偏移处,故第一个成员char类型的的偏移量为零

2.从第二个成员开始,每个成员都要对齐到成员对齐数的整数倍

(对齐数--成员自身大小与默认对齐数的最小值的整数倍,如果自身大小是四,默认对齐数是八,最终的对齐数就是四的倍数),一般情况下默认对齐数就是八。

3.结构体的总大小必须是最大对齐数的整数倍 。

(最大对齐数就是每个成员对齐数中的最大值)

4.如果结构体中嵌套结构体的情况下,嵌套的结构体就对齐到自己成员对齐数的最大对齐数的整数倍处,结构体的总大小就是最大对齐数(含嵌套的结构体成员)的整数倍。

下面其中的一个结构体进行分析:

先向大家介绍一下本章的配角—offsetof

offsetof的返回值就是距离这个结构体(自定义类型)起始位置的值

参数就是结构体的名称和结构体成员的名称。

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
	char a;
	int b;
	char c;
}s;
int main()
{
	//offsetof-是指偏移量
	printf("%d\n", offsetof(s,a));
	printf("%d\n", offsetof(s,b));
	printf("%d\n", offsetof(s,c));
	return 0;
}

char a; //因为char a是结构体第一个成员,所以偏移量就是零

int b;   //自身大小:  4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是四

char c; // 自身大小: 1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八

又因为最终的结构体大小是成员最大对齐数的倍数,也就是四的倍数,所以最终的结构体的大小应该就是十二。

到这里是不是有一定的思路了,别急,再来一道试试吧

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
	double a;
	char b;
	int  c;
}s;
int main()
{
	//offsetof-是指偏移量
	printf("%d\n", offsetof(s,a));
	printf("%d\n", offsetof(s,b));
	printf("%d\n", offsetof(s,c));
	printf("%d", sizeof(s));
	return 0;
}

结果如下:

是不是跟你想的一样呢?

同样的,用一样的方法进行解释

double a;     //因为double a是结构体第一个成员,所以偏移量就是零

char b;     //自身大小:1    默认对齐数:8  对齐数:1的倍数即可,所以偏移量就是八

int  c;        //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是十二

最终结构体的大小就是四的整数倍十六

下面给应该结构体嵌套结构体的例子

#include<stdio.h>
#include<stddef.h>
typedef struct s1
{
	char i;
	char j;
	int k;
}s1;
typedef struct s2
{
	char a;
	int c;
	s1;
}s2;
int main()
{

	printf("%d\n", offsetof(s2, a));
	printf("%d\n", offsetof(s2, c));
	printf("%d", sizeof(s2));
	return 0;
}

我相信此时的你一定会计算结构体想系统申请的大小,以及内存对齐是咋回事

其实,内存对齐也就那么回事儿~

为什么存在内存对齐

知道怎样计算后,你是否和我一样思考

为什么内存的申请不能想main函数中的内存申请一样,要多少就申请相应大小的空间,这样既省内存,也不用考虑这么多。

1.平台的原因

所谓平台原因就是与硬件有关,硬件不能访问内存中的每一个空间,换句话说,就是按一定的规律进行访问,这样内存对齐就起到了很好的作用

2.性能的原因

数据结构(尤其是栈),应该尽可能的在自然边界上对齐

因为我们的CPU访问空间,就是一次性按四个字节的空间来访问,内存对齐在一定的时候避免了访问一次的空间进行了二次访问

如下访问应该int类型内存对齐后只需要访问一次

总的来说内存对齐就是拿空间换取时间

当然,我们可以实现内存对齐之上,也可以进行省一定空间

就想博客开头一道题,一模一样的代码,最终的结构体的大小却不一样,这种就是优化版的结构体

这里给一个小的技巧,就是把空间小的成员尽量放在一起

到此这篇关于C语言结构体中内存对齐的问题理解的文章就介绍到这了,更多相关C语言 内存对齐内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言结构体内存对齐详解

    目录 实例一: 分析:存储结构图如下 实例二: 分析:存储结构如下 实例三: 分析:存储结构如下 实例四: 分析:存储结构图如下 总结 1.结构体内存对齐是指当我们创建一个结构体变量时,会向内存申请所需的空间,用来存储结构体成员的内容.我们可以将其理解为结构体成员会按照特定的规则来存储数据内容. 2.结构体的对齐规则 (1)第一个成员在相比于结构体变量存储起始位置偏移量为0的地址处. (2)从第二个成员开始,在其自身对齐数的整数倍开始存储(对齐数=编译器默认对齐数和成员字节大小的最小值,VS编译

  • C语言复数的加减及输出结构体

    一. #include<stdio.h> typedef struct complex { int real; //实部 int imag; //虚部 }complex; /* 功能:复数加法 参数:两个复数 返回值:两个复数的和 */ complex complexadd(complex x,complex y) { complex sum; sum.real = x.real + y.real; sum.imag = x.imag + y.imag; return sum; } /* 功能

  • C语言位段(位域)机制结构体的特殊实现及解析

    目录 概念 内存分配 位段跨平台问题 作用 Tip 应用场景 概念 什么是位段? 位段又称为位域,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员就叫做称为位段( bit field) .利用位段能够用较少的位数存储数据达到节省空间的目的. 位段是结构体特有的,所以声明是和结构是类似的,但有两个不同: 1. 位段成员必须是 int ,unsigned int,signed int 2. 位段成员名后边结构包括一个冒号和整型数字 举个栗子: struct haha

  • 一起来看看C语言世界中的结构体

    目录 一.结构体的概念: 二.结构体变量的定义和初始化 结构体变量的定义 (1)单独定义 (2)混合定义(在定义结构体的同时定义结构体变量) 结构体变量的初始化 三.结构体变量的使用("."与"->"的使用) (1)"."的使用(1级运算符,结合方向从左到右): (2)"->"的使用(1级运算符,结合方向从左到右): 总结 一.结构体的概念: 结构体是由一批数据聚合而成的结构型数据. 引入结构体,程序设计人员就可以

  • C语言的结构体你了解吗

    目录 结构体内存对齐 结构体传参 结构体实现位段 什么是位段 位段在内存中的存储 位段的问题 总结 结构体内存对齐 当我们创建一个结构体变量时,内存就会开辟一块空间,那么在创建结构体变量时内存到底是怎么开辟空间的呢?会开辟多大的空间呢?我们来看一下下面的代码 struct S { int i; char c; char b; }; struct G { char c; int i; char b; }; int main() { struct S u; struct G g; printf("%

  • C语言中结构体实例解析

    目录 一.结构体定义 二.实例演示 结构体作为函数参数 结构体指针 三.typedef struct 和 struct的区别 1.声明不同 2.访问成员变量不同 3.重新定义不同 总结 一.结构体定义 C语言结构体由一系列相同或者不同类型的数据构成的集合,结构体类型就是以struct关键字定义的数据类型. 结构体的格式如下: struct 结构名称 { 结构体所包含的数据成员,包括变量数组等 } 结构变量 ;//结构变量可以指定一个或多个 举例: struct Student { char na

  • C语言结构体中内存对齐的问题理解

    目录 前言 思考 结构体在内存中开辟空间时内存对齐的规则 为什么存在内存对齐 1.平台的原因 2.性能的原因 前言 学C的同学应该知道~ 想精通C语言就不得不面对—指针与内存 续上次指针的进阶,这一章我来聊一聊C语言内存对齐的问题 学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的 思考 #include<stdio.h> typedef struct s1 { char a; char b; int c; }s1; typedef struct s2 { char a; int c;

  • C语言中结构体与内存对齐实例解析

    1.结构体类型 C语言中的2种类型:原生类型和自定义类型,结构体类型是一种自定义类型. 2.结构体使用时先定义结构体类型再用类型定义变量 -> 结构体定义时需要先定义结构体类型,然后再用类型来定义变量. -> 也可以在定义结构体类型的同时定义结构体变量. // 定义类型 struct people { char name[20]; int age; }; // 定义类型的同时定义变量. struct student { char name[20]; int age; }s1; // 将类型st

  • C语言热门考点结构体与内存对齐详解

    目录 一.引例 1.结构体的第一个成员永远放在结构体起始位置偏移量为0的位置 2.从第二个成员开始,总是放在偏移量为一个对齐数的整数处,对齐数=编译器默认的对齐数和变量自身大小的较小值 3.结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍 二.小试牛刀 三.嵌套结构体的特殊情况 四.关于为什么存在内存对齐 1.平台原因(移植原因): 2.性能原因: 总结 一.引例 到底什么是结构体内存对齐,我们用一段代码来介绍一下 struct S1 { char c1;//1字节 int a;/

  • C语言结构体计算内存占用问题解析

        c语言中结构体使用是非常广泛的,但是结构体有一个问题,就是如果开头的字段属性是字符类型(char),紧跟着的是其他类型,比如整型.长整型.双精度.浮点型,这时候结构体的大小会发生改变,下面给出一个示例: #include <stdio.h> struct person{ char sex; int age; char name[8]; }; int main() { printf("sizeof(person) = %d\n",sizeof(struct perso

  • C语言中结构体的内存对齐规则讲解

    目录 1.结构体的内存对齐规则 2.例子 3.为什么存在内存对齐 4.如何修改默认对齐数 1.结构体的内存对齐规则 1.第一个成员在与结构体变量偏移量为0的地址处. 2.其他成员变量都放在对齐数(成员的大小和默认对齐数的较小值)的整数倍的地址处. 对齐数=编译器默认的一个对齐数与该成员大小的较小值.(VS中默认的对齐数是8) 3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数 )的整数倍. 4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最

  • C语言程序中结构体的内存对齐详解

    目录 一.为什么存在内存对齐 二.结构体的内存对齐四规则 三.举例 一.为什么存在内存对齐 1.平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的:某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常. 2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐. 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问:而对齐的内存访问仅需要一次访问. 总的来说结构体的内存对齐是拿空间来换取时间的做法. 二.结构体的内存对齐四规则 默认情况:默认的对

  • C语言 详细分析结构体的内存对齐

    目录 一.结构体 二.结构体内存对齐 1.非嵌套结构体的大小 2.含嵌套结构体的大小 三.为什么要内存对齐 1.平台原因(移植原因) 2.性能原因 一.结构体 结构体 (struct)是一种数据结构,可以包含很多数据类型,可以实现比较复杂的数据结构. 常见的int,char类型变量,我们可以一眼看出占多少字节,但对于结构体,可就有点难度了. 让我们来猜猜以下程序的输出 struct S1 { char c1; int i; char c2; }; struct S2 { char c1; cha

  • C语言详解结构体的内存对齐与大小计算

    目录 结构体的内存对齐 1.计算结构体的大小 2.结构体的对齐规则 3.为什么存在内存对齐? 4.总结 结构体的内存对齐 1.计算结构体的大小 struct S1 { char c1; // 1 byte,默认对齐数为8,所以c1的对齐数是1,第一个成员变量放在与结构体变量偏移量为0的地址处 int i; // 4 byte,默认对齐数为8,所以i的对齐数是4,所以i要放到偏移量为 4的整数倍 的地址处 char c2; // 1 byte,默认对齐数为8,所以c2的对齐数是1,所以c2要放到偏

  • C语言详细分析结构体的内存对齐规则

    目录 引例 结构体内存对齐规则 那么为什么要有内存对齐呢 如何优化 修改默认对齐数 结构体的内存对齐是一个特别热门的知识点! 引例 #include<iostream> using namespace std; struct S { char c; // 1 int a; // 4 char d; // 1 }; int main() { struct S s = { 'a',2,'y'}; cout << sizeof(struct S) << endl;// 12

  • C语言结构体占用内存深入讲解

    前言 前几天有个小朋友问了我一下,关于C语言结构体占用空间的问题.觉得以后会对小可爱有点帮助,就打算先写一下. struct Test { int a; char b; int c; } test; 理论上,结构体中的各个成员在内存中应该是连续储存的,就像数组里面的元素一样.事实上,也确实是这个样子的,不过和我们想象的有点不一样. 按照我们最初的想法,变量test所占的内存为 4 + 1 + 4 = 9. 但是我们写一个小代码验证一下发现和我们想的不一样. 它的内存为12.因为 int类型是4个

随机推荐