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

一、相关概念

(1)数据类型自身对齐值:基本数据类型的自身所占空间大小。

(2)指定对齐值:使用#pragam pack(value)时,指定的对齐值value。

(3)结构体或类的自身对齐值:其中成员对齐值最大的那个值。

(4)结构体和类的有效对齐值:自身对其值和指定对其值中较小的那个值。

二、示例代码

1、示例一

32位机器上定义如下结构体:

struct xx
{
long long _x1;
char _x2;
int _x3;
char _x4[];
static int _x5;
};
int xx::_x5;

正确答案是24。

你做对了么?下面给出解释:

每个元素的起始偏移地址要能被其类型大小整除,结构体整体大小要能被结构体中最大数据类型整除。

结构体的有效对齐值的确定:

  1. 当未明确指定时,以结构体中最长的成员的长度为其有效值
  2. 当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为其值。
  3. 当用__attribute__ ((__packed__))指定长度时,强制按照此值为结构体的有效对齐值

2、示例二

32位环境下,给定结构体

struct A
{
char t:;
char k:;
unsigned short i:;
unsigned long m;
};
问 sizeof ( A ) =_____;

答案是8,这次你做对了么?

解析:变量后面加 :  然后加数字表示位域,也就是说着代表按位来存放的,不是按字节,这是计算机为了节约空间的一种方式。char 类型是一个字节(8个位),又因为 t 和 k 加起来刚好8位,也就是一个字节,所以存储在一个位。然后 short 占一共16个位,需要从地址为2的倍数的位置存储,所以前边空出一个字节。又因为放了8个,剩下8个不够后面long存放,所以算两个字节。因为long在32是4个字节,所以一共 1 + 1 + 2 + 4 = 8。然后再进行结构体对齐,所以最终结果就是 8。

三、知识点

1、位域的sizeof

  1. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
  2. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
  3. 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
  4. 如果位域字段之间穿插着非位域字段,则不进行压缩;
  5. 整个结构体的总大小为最宽基本类型成员大小的整数倍。

2、内存对齐的3大规则

  1. 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
  2. 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
  3. 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型

作者:耑新新,发布于  博客园

转载请注明出处,欢迎邮件交流:zhuanxinxin@aliyun.com

C/C++有效对齐值的确定的更多相关文章

  1. 小甲鱼PE详解之区块描述、对齐值以及RVA详解(PE详解06)

    各种区块的描述: 很多朋友喜欢听小甲鱼的PE详解,因为他们觉得课堂上老师讲解的都是略略带过,绕得大家云里雾里~刚好小甲鱼文采也没课堂上的教授讲的那么好,只能以比较通俗的话语来给大家描述~ 通常,区块中 ...

  2. (转)CPU Cache与内存对齐

    转自:http://blog.csdn.net/zhang_shuai_2011/article/details/38119657 原文如下: 一. CacheCache一般来说,需要关心以下几个方面 ...

  3. C语言:内存字节对齐详解[转载]

    一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...

  4. struct内存对齐1:gcc与VC的差别

    struct内存对齐:gcc与VC的差别 内存对齐是编译器为了便于CPU快速访问而采用的一项技术,对于不同的编译器有不同的处理方法. Win32平台下的微软VC编译器在默认情况下采用如下的对齐规则:  ...

  5. Nginx学习笔记(五) 源码分析&内存模块&内存对齐

    Nginx源码分析&内存模块 今天总结了下C语言的内存分配问题,那么就看看Nginx的内存分配相关模型的具体实现.还有内存对齐的内容~~不懂的可以看看~~ src/os/unix/Ngx_al ...

  6. ARM字节对齐问题详解

    一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这 ...

  7. C语言中内存对齐方式

    一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...

  8. C语言之字节对齐

    在C语言编程中,有时为了达到减少运行的时间的目的,需要浪费一些空间:而有时为了节省空间,使它的运行时间增长.而字节对齐则是为了访问效率,用空间换取时间. 要掌握字节对齐,首先得明确一下四个概念: 1. ...

  9. C ~ C语言字节对齐

    1. 什么是对齐? 现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型 ...

随机推荐

  1. 我为什么放弃MySQL?选择了MongoDB

    最近有个项目的功能模块,为了处理方便,需要操作集合类型的数据以及其他原因.考虑再三最终决定放弃使用MySQL,而选择MongoDB. 两个数据库,大家应该都不陌生.他们最大的区别就是MySQL为关系型 ...

  2. c++/ boost 库常见错误及解决方法总结

    1. error LNK2019: 无法解析的外部符号 "class boost::system::error_category const & __cdecl boost::sys ...

  3. BZOJ5416 NOI2018冒泡排序(动态规划+组合数学)

    打表可以发现相当于不存在长度>=3的递减子序列. 考虑枚举在哪一位第一次不卡限制.注意到该位一定会作为前缀最大值.判掉已确定位不合法的情况后,现在的问题即为求长度为i.首位>j的合法排列个 ...

  4. group replication && Galera replication

    不愧是 Oracle 的 MySQL Community Manager,把对手的 Galera Cluster 讲得一无是处. http://lefred.be/content/group-repl ...

  5. HGOI20180831 NOIP2018模拟

    input1: 4 4 4 4 4 3 2 4 5 4 5 5 5 1 7 3 2 output1: Yes Yes Yes No 好的吧数学题QwQ考场上没人做出来qwq 就是判断两个矩形能否互相放 ...

  6. Qt QGraphicsItem 绕中心旋转、放缩

    最近用到了QGraphicsItem,可以通过QGraphicsItemAnimation使其产生动画效果. QGraphicsItemAnimation自带了setPosAt().setRotati ...

  7. (转)eclipse设置默认编码格式为UTF-8

    设置 需要设置的几处地方为: Window->Preferences->General ->Content Type->Text->JSP 最下面设置为UTF-8,可以设 ...

  8. PHP内核-代码的执行(二)

    学习来源:http://www.php-internals.com/book/?p=chapt02/02-00-overview 最开始学习PHP的时候感觉上手真的好容易,噼里啪啦一个回车 “Hell ...

  9. Linux上case用法

    Linux上case用法示例: #!/bin/bash # This is a script for test case ASK_COUNT=$ #从参数获取该变量的值 # if [ -z " ...

  10. Linux shell 日期,时间相关的命令

    在shell脚本中,经常要用到跟获取日期相关的东西,这里记录一下Linux shell 获取日期的方法 获取当前日期:today=`date +"%Y-%m-%d"` 获取昨天的日 ...