关键字 对齐 内存对齐

数据对齐/内存对齐 && 数据格式 字、双字、四字在自然边界上不需要在内存中对齐。(什么叫做字?见数据格式) 对字、双字、四字来说,自然边界分别是偶数地址、可以被4整除的地址、可以被8整除的地址。 无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;然而,对齐的内存仅需要一次访问。 未对齐的:一个字或双字操作数跨越了4字节边界,或者一个四 阅读详情


关键字 对齐 内存对齐



原作者姓名 Fang 

正文
什么是内存对齐

    考虑下面的结构:

         struct foo
         {
           char c1;
           short s;
           char c2;
           int i;
          };
    
    
假设这个结构的成员在内存中是紧凑排列的,假设c1的地址是0,那么s的地址就应该是1,c2的地址就是3,i的地址就是4。也就是
    c1 00000000, s 00000001, c2 00000003, i 00000004
。

    可是,我们在Visual c/c++ 6中写一个简单的程序:

         struct foo a;
    printf("c1 %p, s %p, c2 %p, i %p/n",
        (unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
    
运行,输出:
         c1 00000000, s 00000002, c2 00000004, i 00000008
。

    为什么会这样?这就是内存对齐而导致的问题。

为什么会有内存对齐

    以下内容节选自《Intel Architecture 32 Manual》。
    
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)
    
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
    
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
    
某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。

编译器对内存对齐的处理

    缺省情况下,c/c++编译器默认将结构、栈中的成员数据进行内存对齐。因此,上面的程序输出就变成了:
c1 00000000, s 00000002, c2 00000004, i 00000008
。
编译器将未对齐的成员向后移,将每一个都成员对齐到自然边界上,从而也导致了整个结构的尺寸变大。尽管会牺牲一点空间(成员之间有空洞),但提高了性能。
也正是这个原因,我们不可以断言sizeof(foo) == 8。在这个例子中,sizeof(foo) == 12。

如何避免内存对齐的影响

    那么,能不能既达到提高性能的目的,又能节约一点空间呢?有一点小技巧可以使用。比如我们可以将上面的结构改成:

struct bar
{
    char c1; 
    char c2;
    short s;
    int i;
};
    
这样一来,每个成员都对齐在其自然边界上,从而避免了编译器自动对齐。在这个例子中,sizeof(bar) == 8。

    这个技巧有一个重要的作用,尤其是这个结构作为API的一部分提供给第三方开发使用的时候。第三方开发者可能将编译器的默认对齐选项改变,从而造成这个结构在你的发行的DLL中使用某种对齐方式,而在第三方开发者哪里却使用另外一种对齐方式。这将会导致重大问题。
    
比如,foo结构,我们的DLL使用默认对齐选项,对齐为
c1 00000000, s 00000002, c2 00000004, i 00000008
,同时sizeof(foo) == 12。
而第三方将对齐选项关闭,导致
    c1 00000000, s 00000001, c2 00000003, i 00000004
,同时sizeof(foo) == 8。

如何使用c/c++中的对齐选项

    vc6中的编译选项有 /Zp[1|2|4|8|16] ,/Zp1表示以1字节边界对齐,相应的,/Zpn表示以n字节边界对齐。n字节边界对齐的意思是说,一个成员的地址必须安排在成员的尺寸的整数倍地址上或者是n的整数倍地址上,取它们中的最小值。也就是:
    min ( sizeof ( member ),  n)
    
实际上,1字节边界对齐也就表示了结构成员之间没有空洞。
    /Zpn
选项是应用于整个工程的,影响所有的参与编译的结构。
    
要使用这个选项,可以在vc6中打开工程属性页,c/c++页,选择Code Generation分类,在Struct member alignment可以选择。

    要专门针对某些结构定义使用对齐选项,可以使用#pragma pack编译指令。指令语法如下:
#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n  )
    
意义和/Zpn选项相同。比如:

#pragma pack(1)
struct foo_pack
{
    char c1;
    short s;
    char c2;
    int i;
};
#pragma pack()

栈内存对齐

    我们可以观察到,在vc6中栈的对齐方式不受结构成员对齐选项的影响。(本来就是两码事)。它总是保持对齐,而且对齐在4字节边界上。

验证代码

#include <stdio.h>

struct foo
{
    char c1;
    short s;
    char c2;
    int i;
};

struct bar
{
    char c1; 
    char c2;
    short s;
    int i;
};

#pragma pack(1)
struct foo_pack
{
    char c1;
    short s;
    char c2;
    int i;
};
#pragma pack()


int main(int argc, char* argv[])
{
    char c1;
    short s;
    char c2;
    int i;

    struct foo a;
    struct bar b;
    struct foo_pack p;

    printf("stack c1 %p, s %p, c2 %p, i %p/n",
        (unsigned int)(void*)&c1 - (unsigned int)(void*)&i,
        (unsigned int)(void*)&s - (unsigned int)(void*)&i,
        (unsigned int)(void*)&c2 - (unsigned int)(void*)&i,
        (unsigned int)(void*)&i - (unsigned int)(void*)&i);

    printf("struct foo c1 %p, s %p, c2 %p, i %p/n",
        (unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
        (unsigned int)(void*)&a.i - (unsigned int)(void*)&a);

    printf("struct bar c1 %p, c2 %p, s %p, i %p/n",
        (unsigned int)(void*)&b.c1 - (unsigned int)(void*)&b,
        (unsigned int)(void*)&b.c2 - (unsigned int)(void*)&b,
        (unsigned int)(void*)&b.s - (unsigned int)(void*)&b,
        (unsigned int)(void*)&b.i - (unsigned int)(void*)&b);

    printf("struct foo_pack c1 %p, s %p, c2 %p, i %p/n",
        (unsigned int)(void*)&p.c1 - (unsigned int)(void*)&p,
        (unsigned int)(void*)&p.s - (unsigned int)(void*)&p,
        (unsigned int)(void*)&p.c2 - (unsigned int)(void*)&p,
        (unsigned int)(void*)&p.i - (unsigned int)(void*)&p);

    printf("sizeof foo is %d/n", sizeof(foo));
    printf("sizeof bar is %d/n", sizeof(bar));
    printf("sizeof foo_pack is %d/n", sizeof(foo_pack));
    
    return 0;
}

正文完

 

 
C语言结构体字节对齐那些坑:用__packed关键字省内存,到底值不值? 本文深入探讨了C语言结构体字节对齐的优化与陷阱,重点分析了`__packed`关键字在节省内存与性能损耗之间的权衡。通过实际案例和性能数据,揭示了在嵌入式开发中如何合理使用字节对齐策略,避免系统崩溃和性能下降,同时提供了现代编译器的优化技巧和调试方法。 阅读详情

相关推荐

C++11新增关键字~alignas(struct对齐、sizeof、alignof)

本文记录alignas关键字,同时介绍alignof和sizeof.

m0_68070522的博客 8618

C语言中对齐概念的理解

 c语言中对齐概念:问题:1.什么是对齐?答:变量要放到存储器中,如何放就产生了对齐问题。一般说来,如果一个变量需要占X个字节,则该量的起始地址必须能够被X整数。这就是所谓的对齐。如果一个变量大小是一个字,则字对齐即可,如果是两个字,则双字对齐2.对齐是对什么而言?只是结构体中的变量吗?答:一般对一个(变)量而言,结构包括多个量,所以也存在对齐问题3.为什么要使用对

lqhtoby的专栏 2366

HyperMesh实战:5种复杂载荷场景下的field映射技巧(附TCL脚本)

本文详细介绍了HyperMesh在5种复杂载荷场景下的field映射技巧,包括轴承载荷的圆柱坐标系映射、粉末压力中的切向力处理、实验数据到有限元模型的场映射、多工况载荷的组合映射以及局部细化网格的边界条件传递。通过实战案例和TCL脚本,帮助工程师高效解决有限元分析中的载荷映射难题,提升工作效率。

fanta的博客 295

字节对齐

什么是字节对齐,为什么要对齐      现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。   作用和原因: 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某

barbarian_zc的专栏 625

ARM Cortex平台NEON指令集优化实战指南

本文为ARM Cortex平台开发者提供了一份全面的NEON指令集优化实战指南。文章从NEON的SIMD架构原理讲起,详细介绍了开发环境搭建、NEON内联函数与自动向量化两种核心编程方法、关键数据类型与指令,并通过图像饱和运算、矩阵乘法等实战案例,深入解析了性能调优技巧与常见避坑指南,旨在帮助开发者充分释放ARM处理器的并行计算潜力。

weixin_29162439的博客 261

COCOS 3.8 接入高德定位SDK

/微信登录所必须的code。//是否获得code。

八喜互动 1995

Delphi中的内存对齐 与 Packed关键字

 以delphi为例:TTest = recordc1: char;i1: Integer;c2: char;c3: Char;end;这个结构如果用sizeof取其占用的内存大小,是多少呢,是1+4+1+1=7么,不是,是4*3 = 12; 这是因为32位编译的时候,默认结构会自动内存对齐(32bit = 4byte)。如果要想让这个结构占用7个字节的话,必须加上packed关键字。如下

笑看人生 坐看云起 4206

一篇文章将三极管讲透:三极管从原理到应用,从参数到特性,从入门到精通

晶体三极管(Transistor)是一种半导体电子器件,也是电子工程中最基本的元件之一。它有三个区域,分别是P型半导体,N型半导体和P型半导体,从而形成PNP型晶体三极管或者NPN型晶体三极管。

学习帮的博客 9万+

内存对齐与__align()关键字

内存对齐是指在内存中对数据进行存储的一种方式,通常是使数据的起始地址符合特定的规则存储,例如使数据的起始地址按照4字节边界对齐,即数据的起始地址可以被4字节整除。

m0_55772787的博客 406

【天工Godwork精品教程】天工3.1.7安装教程(附Godwork完整版下载地址)

本文讲解天工3.1.7安装过程(附Godwork完整版网盘下载地址)。 一、天工3.1.7安装教程 1. 安装GodWork-AT 3.1.7 2. 安装GodWork-AT 3.1.7补丁 3. 安装GodWork-EOS-Setup-2017B-1231 4. 安装GodWork-EOS补丁 5. 运行godwokr软件 6. 生成ZC码 7. 输入ZC码 8. eos插

智慧空间实验室 5287

【数据分享】2012-2022年全国及各城市POI(兴趣点)数据(超20G)

POI(一般作为Point of Interest的缩写,也有Point of Information的说法),通常称作兴趣点,泛指互联网电子地图中的点类数据,基本包含名称、地址、坐标、类别四个属性;随着互联网电子地图服务与LBS应用的普及,POI无论从概念范畴,还是从信息纵深都有了长足发展,互联网各个风口或火山口都和POI有一定关系,如O2O、电商、社交、互联网金融、共享经济等。

J_Giser的博客 2741

内存对齐和sizeof关键字

关于内存对齐的文章很多,大家上网搜一下会发现很多的文章讲的很细,我在这里就不多提,我主要提出一些我总结的一些关于这种体型的几个细节和做题依据。1、我们内存对齐总是选择min(编译器默认的对齐字节,结构体中所占字节最大的数据类型)按照这个字节数对齐     注意:我们的32位编译器默认是4字节,64位默认是8字节2、我们结构体中每个数据的起始地址必须是本个数据类型的整数倍大小,例如int 类型数据的...

Betty2017的博客 439

高通SDX12:ProSLIC Si32185移植调试

高通 SDX12 语音芯片slic 音频驱动 Si32185

不秃头的程序猿Gabriel的博客 2038

7、内存对齐新增关键字

1、第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 2、在数据成员完成各自对齐之后,类(结构或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。   很明显#pragma pack(n)作为一个预编译指令用来设置多少个字节对齐的。值得注意的是,n的缺省数值是按照编译器自身设置,一般为8,合法的数值分别是1、2、4、8、16。   即

zd845101500的博客 216

数据挖掘实战-基于情感分析+网络语义分析+LDA主题分析对大唐不夜城用户评论进行文本分析

本研究基于去哪儿网和携程网的1888条大唐不夜城游客评论数据,运用Python进行文本分析。通过情感分析发现游客评价以积极为主(占比约70%),中性占20%,消极占10%。采用ROSTCM6软件进行社会网络语义分析,识别不同情绪下的高频词汇。使用LDA主题模型将评论划分为3个主题(夜景、表演、美食),并分析主题强度随时间变化趋势。实验包含数据采集、预处理、情感分析、语义网络分析和LDA建模等完整流程,为景区管理优化提供数据支持。源代码涵盖爬虫、数据处理和可视化分析的全套实现。

m0_64336780的博客 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

C/C++关键字(sizeof(含内存对齐),typedef,static,const,inline)

sizeof()是 C/C++ 中的一个运算符(不是函数),获取对象或类型以字节为单位的内存大小。它在求值,不会产生运行时开销。sizeof\0sizeof()首先这个联合体的大小得看其中最大成员结构的内存大小,结构体u的大小为12字节,而k是4字节,这个联合体一共是12字节。x和k的内存空间是同一块,k赋值为0后,通过x去访问,它的值还是0。

guaixiaohuo的博客 1924

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

struct关键字及内存对齐详解

struct关键字空结构体有多大?struct student { }stu; cout<<sizeof(stu)<<endl;//在vc6.0下是1 因为为需要一个字节来标记这里有个结构体,否则如果是0的话,定义下一个结构体的时候,会和空结构体公用一个地址,无法分别。 结构体不能递归自包含定义,如下: struct A { int i; B b; } struct B {

月已满西楼的博客 994

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++11之explicit关键字、左值与右值、函数返回值当引用、结构体内存对齐

explicit关键字、左值与右值、函数返回值当引用、结构体内存对齐

procurar的博客 611

[C++关键字] alignof & alignas 内存对齐 sizeof 占内存大小

直接上代码测试是入门神器,以结构体为例,解释“对齐”和“补齐”概念。 #include <iostream> struct Empty {}; struct Foo { int f2; double f1; char c; }; struct alignas(16) FooNew { int f2; double f1;...

weixin_30872733的博客 233

CMD文件中的关键字ALIGN

表示内存对齐,ALIGN(1024)表示这块内存的首地址必须能被1024整除,在算FFT时,有几个FFT函数要求分配的地址必须按照N*2的地址对齐,那就必须使用ALIGN关键字。 若不使用此关键字则由系统分配地址。 ...

超级张大侠的博客 1874

C++ Learning 内存对齐

简要介绍C++中的内存对齐

2301_79744389的博客 1007

ARM 内存对齐总结

一、啥是内存对齐?为啥要内存对齐?       现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问都可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就是对齐。 字节对齐的原因大致是如下两条:       1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据

myxmu的专栏 3897

结构体内存对齐问题

c++内存对齐

qq_40797283的博客 546
上一篇: 在Visual C++中使用内联汇编
下一篇: 用V C++检测和隔离内存泄漏
Image_Graphics
博客等级 码龄20年 18粉丝 52原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值