文章目录

  • sizeof()
  • 内存对齐
    • 内存对齐的背景
    • 全部规则汇总(看这里)
    • 典型例子:
    • Pragma Pack(n)与内存分配
    • #pragma pack对对齐模数的影响
  • 偏移量

sizeof()

对于数据类型的sizeof,取决于CPU位数,编译器,汇编等。
通常来说
32位

指针都是  4个字节char     1个字节
short 两个字节
int      4个字节
long     4个字节
long int 4个字节
float    4个字节double    8个字节
long double  8个字节

64位

指针都是一个字长, 8个字节char    1个字节
short   2个字节
int     4个字节 long    8个字节
long int  8个字节
double    8个字节
long double 也可以变长了, 16个字节

内存对齐

内存对齐的背景

因为计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
例如:

typedef struct mA{int a;char b;short c;
}A;

假如我们不使用字节对齐,那么这个结构体就是4+1+2=7个字节,但是我们实际打印确是8个字节。

应用:
但是在实际工程中,如果我们是读取一块一块的数据,这些数据都是连在一起的,比如bmp图片,前14个字节是文件信息头,紧接着是40个字节的图像信息头。如果我们不用结构体对齐操作的话。那就乱了套了,数据就读取失败。 所以我们要在结构体前加上#Pragma Pack(1),以一个字节对齐,使用完后要加#pragma pack(pop),释放内存对齐。为啥要以一个字节对齐呢?是因为一般的数据类型都是大于等于1个字节的。这样的话就会按照数据类型原有的的分配。就不会错位了。

#pragma pack(push)#pragma pack(2)//因为变量最小是short,大小是2字节,所以按2字节对齐也行。最好是1字节对齐。typedef struct tagBITMAPINFOHEADER
{unsigned int      biSize;int               biWidth;int               biHeight;unsigned short     biPlanes;unsigned short     biBitCount;unsigned int      biCompression;unsigned int      biSizeImage;int               biXPelsPerMeter;int               biYPelsPerMeter;unsigned int      biClrUsed;unsigned int      biClrImportant;
} BITMAPINFOHEADER;typedef struct tagBITMAPFILEHEADER {unsigned short    bfType;unsigned int     bfSize;unsigned short    bfReserved1;unsigned short    bfReserved2;unsigned int     bfOffBits;
} BITMAPFILEHEADER;#pragma pack(pop)

全部规则汇总(看这里)

1.结构体内,每个变量按xx字节对齐,实际的体现的效果是总大小是xx的倍数


如果#pragma pack()参与了对对齐模数的设定,则取pack设定的,系统默认的,结构体内参数的最大型,三者中的最小。最终结构体大小要是对齐模数的倍数。

结构体里面static变量,因为静态变量的存放位置与结构体实例的存储地址无关,是单独存放在静态数据区的,因此用siezof计算其大小时没有将静态成员所占的空间计算进来。
静态成员如:

typedef struct mC
{static double d;//内存上完全不考虑静态变量short c;
}C;

结构体大小为2。

例如:

typedef struct mC
{char b;int a;short c;
}C;

大小是12。64位系统,对齐数,取8和最大的int型4之间的最小,为4.

typedef struct mC
{short c;
}C;

大小为2。64位系统,对齐数,取8和最大的shrort型2之间的最小,为2.
如果这里加了#pragma pack(4),取设定的4,系统的8,最大的类型short大小2,三者的最小为2.最终结构体大小是2的倍数

typedef struct mC
{double d;char b;int a;short c;
}C;//20 24
C test;
printf("sizeof=%d",sizeof(test));

32位系统是20,64位系统是24.
一般VS工程按默认设置:

(另外,VS配置管理器那配置的win32和x64并没起到调整4,和8的作用,还是按系统来的)
2.具体变量的对齐地址规则。可得到结构体内每个变量的地址,和结构体总大小。
例如:

 struct   A
{int a;char b;double c;char d;
};
printf("sizeof=%d",sizeof(struct A));

在windows系统32位平台上: 默认按4字节对齐。
int占4个字节
char占1个字节
float占4个字节
double占8个字节

注意是最基础的,地址是连续递增,即:上面的结构体A是按,a,b,c,d的顺序写的,那内存地址也要按a,b,c,d的顺序放,不能跳过变成如a,b,d,c.

int a从0偏移开始,占四个字节,即占用0,1,2,3,现在可用偏移为4偏移,接下来存char b; 由于4是1的倍数,故而,b占用4偏移,接下来可用偏移为5偏移,接下来该存double c; 由于5不是8的倍数,所以向后偏移5,6,7,都不是8的倍数,偏移到8时,8是8的倍数,故而c从8处开始存储,占用8,9,10,11,12,13,14,15偏移,现在可用偏移为16偏移,最后该存char d ;因为16是1的倍数,故d占用16偏移,接下来在整体向后偏移一位,现处于17偏移,min(默认对齐参数,类型最大字节数)=8;因为17不是8的倍数,所以继续向后偏移18…23都不是8的倍数,到24偏移处时,24为8的整数倍,故而,该结构体大小为24个字节。

即:该变量存放的地址(从0,开始),必须是该变量类型大小的倍数。

典型例子:

64位系统下,默认按8字节对齐

typedef struct mC
{double d;int a;char b;short c;
}C;C mTest;
printf("sizeof=%d\n",sizeof(mTest));
printf("%p,%p,%p,%p",&mTest.d,&mTest.a,&mTest.b,&mTest.c);



注意,如果调换int 和char的位置,总长度变成24了

typedef struct mC
{double d;char b;int a;short c;
}C;C mTest;
printf("sizeof=%d\n",sizeof(mTest));
printf("%p,%p,%p,%p",&mTest.d,&mTest.b,&mTest.a,&mTest.c);


同样画图:

Pragma Pack(n)与内存分配

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

#pragma pack对对齐模数的影响

1)未指定#pragma pack时,系统默认的对齐模数(32位系统4,64位系统8)。
2)指定#pragma pack 对齐模数时,实际取pack 对齐模数和默认的最小值。
比如32位机:
#pragma pack(8),取8和4的最小值4,对齐.
#pragma pack(2),取2和4的最小值2,对齐.
3)结构体里面static变量,因为静态变量的存放位置与结构体实例的存储地址无关,是单独存放在静态数据区的,因此用siezof计算其大小时没有将静态成员所占的空间计算进来。

#pragma  pack (push,2)     作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为2个字节对齐#pragma pack(pop)            作用:恢复对齐状态

#pragma pack(push)
#pragma pack(2)
#pragma pack(pop)            作用:恢复对齐状态

偏移量

如何知道结构体某个成员相对于结构体起始位置的偏移量?
使用offsetof宏来判断结构体中成员的偏移地址。使用offsetof宏需要包含stddef.h头文件,该宏定义如下:

 #define offsetof(type,menber) (size_t)&(((type*)0)->member)

巧妙之处在于将地址0强制转换为type类型的指针,从而定位到member在结构体中偏移位置,编译器认为0是一个有效的地址,从而认为0是type指针的起始地址。

C语言 结构体,内存对齐,对齐参数,偏移量相关推荐

  1. C语言结构体-大小,对齐,填充,使用及其他

    C语言结构体-大小,对齐 C语言中的结构体(struct)的定义 在C语言中,最常用的数据结构就是结构体了,结构体也是其它数据结构(比如链表等)的基础,结构体的使用非常简单. 比如,定义一个结构体: ...

  2. 关于C语言结构体数组如何作为参数传入函数

    1.不多说上代码 #include<stdio.h> typedef enum {female,male }Sextype; typedef struct {Sextype sextype ...

  3. c语言 结构体指针做函数参数

    demo:修改某个学生的成绩 不利用指针直接在主函数内修改学生成绩的代码: #include <stdio.h> #include <string.h> #define N 5 ...

  4. c语言结构体变量所占字节计算,【C语言】结构体占用字节数及存储与空间分配...

    我们都知道在数据类型中,char类型占1个字节,short占2个字节,int占4个字节,long占8个字节等等. 在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取 ...

  5. c语言的结构体能存放函数吗,在C语言结构体中添加成员函数

    我们在使用C语言的结构体时,经常都是只定义几个成员变量,而学过面向对象的人应该知道,我们定义类时,不只是定义了成员变量,还定义了成员方法,而类的结构和结构体非常的相似,所以,为什么不想想如何在C语言结 ...

  6. C语言结构体的大小 — — 内存对齐和位域

    C语言结构体对齐 C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结 ...

  7. C语言结构体对齐[转]

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  8. C语言结构体字节对齐规则

    C语言结构体字节对齐规则 基本规则 规则1 :结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在 ...

  9. C语言结构体对齐详解

    文章目录 一.C语言结构体对齐大小快速判断 二.反汇编角度看结构体 三.总结 一.C语言结构体对齐大小快速判断 在C语言中定义一个结构体,里面具体占用多少个字节呢,先举一个例子,如下: #includ ...

最新文章

  1. 【未来研究】城市云脑是互联网云脑的节点,城市云脑之间如何互补与支撑
  2. iOS主线程耗时检测方案
  3. 阿里云服务器Linux配置数据库、jre、tomcat、部署javaweb
  4. raid0+磁盘加密
  5. SpringBoot用Servlet处理请求
  6. java中数组的返回值是什么类型_Java数组也是一种数据类型
  7. 计算机系统无法启动 错误恢复怎么办,我电脑在重装系统时出现windows错误恢复怎么办?...
  8. SLAM 建立局部二维栅格地图的一种方法
  9. Android Studio 常用快捷键
  10. ai时代大学生的机遇和挑战_评估AI对美术的影响:威胁或机遇
  11. 关于OMC链接LANSWITCH
  12. 腾讯觅影正式对外开放,可用AI进行医学图像分析和辅助诊疗
  13. C#毕业设计——基于C#+ASP.NET+SQL Server的酒店入住信息管理系统设计与实现(毕业论文+程序源码)——酒店入住信息管理系统
  14. 【二〇二一·立春】读书笔记
  15. 30天自制C++服务器
  16. android camera2 API流程分析
  17. Fluent API
  18. PCIE 2.0协议概念基本科普
  19. 诺奖得主公司CAR-T细胞疗法临床试验现患者死亡,系今年第6例-1
  20. python asyncio_python中asyncio模块

热门文章

  1. Java毕设项目蛋糕店会员系统计算机(附源码+系统+数据库+LW)
  2. 嵌入式计算机外接屏幕没反应怎么办,笔记本外接显示器的嵌入式扬声器没有声音...
  3. 电力电子变换器的科研创新思路(二)
  4. 云应用系统开发技术考点(面试题相关)
  5. android简单计时器源码,Android 实现一个计时器
  6. 水质中的PH值、TDS值、KH值、GH值分别是什么意思
  7. 服务器杀毒软件推荐--服务器安全狗2合1杀毒版来啦
  8. Java——抽象类+模板设计模式
  9. linux 七宗罪.
  10. three.js模糊玻璃效果