范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

嵌入式C语言自我修养地址对齐的核心思想

  嵌入式C语言自我修养-地址对齐的核心思想
  7.1属性声明:aligned
  GNU C通过 __atttribute__来声明 aligned和 packed属性,指定一个变量或类型的对齐方式。这两个属性用来告诉编译器:在给变量分配存储空间时,要按指定的地址对齐方式给变量分配地址。如果你想定义一个变量,在内存中以8字节地址对齐,就可以这样定义。
  inta__attribute__((aligned(8));
  通过 aligned属性,我们可以直接显式指定变量 a在内存中的地址对齐方式。aligned有一个参数,表示要按几字节对齐,使用时要注意地址对齐的字节数必须是2的幂次方,否则编译就会出错。
  什么是数据对齐
  一般情况下,当我们定义一个变量,编译器会按照默认的地址对齐方式,来给该变量分配一个存储空间地址。如果该变量是一个 int型数据,那么编译器就会按4字节或4字节的整数倍对齐;如果该变量是一个 short型数据,那么编译器就会按2字节或2字节的整数倍边界对齐;如果是一个 char类型的变量,那么编译器就会按照1字节对齐。
  inta=1;
  intb=2;
  charc1=3;
  charc2=4;
  intmain(void)
  {
  printf("a: %p ",&a);
  printf("b: %p ",&b);
  printf("c1:%p ",&c1);
  printf("c2:%p ",&c2);
  return0;
  }
  在上面的程序中,我们分别定义2个 int型变量,2个 char型变量,然后分别打印它们的地址,运行结果如下。
  a:00402000b:00402004c1:00402008c2:004这个地址不是4字节对齐的。编译器空出3个字节单元,直接从 0x0040200C这个地址上给变量 c2分配存储空间。
  为什么要数据对齐?
  通过 aligned这个属性声明,我们虽然可以显式指定变量的地址对齐方式,但是也会因边界对齐造成一定的内存空洞,浪费一定的内存空间。比如在上面这个程序中,0x00402009~0x0040200b这三个地址空间的存储单元就没有被使用。
  既然地址对齐会造成一定的内存空洞,那我们为什么还要按照这种对齐方式去存储数据呢?一个主要原因就是,这种对齐设置可以简化 CPU和内存 RAM之间的接口和硬件设计。比如一个32位的计算机系统,CPU读取内存时,硬件设计上可能只支持4字节或4字节倍数对齐的地址访问,CPU每次往内存 RAM读写数据时,一个周期可以读写4个字节。如果我们把一个数据放在4字节对齐的地址上,那么CPU一次就可以把数据读写完毕;如果我们把一个 int型数据放在一个非4字节对齐的地址上,那 CPU就要分2次才能把这个4字节大小的数据读写完毕。
  为了配合计算机的硬件设计,编译器在编译程序时,对于一些基本数据类型,比如 int、char、short、float等,会按照其数据类型的大小进行地址对齐,按照这种地址对齐方式分配的存储地址,CPU一次就可以读写完毕。虽然边界对齐会造成一些内存空洞,浪费一些内存单元,但是在硬件上的设计却大大简化了。这也是编译器给我们定义的变量分配地址时,不同类型变量按不同字节数地址对齐的原因。
  除了 int、char、short、float这些基本类型数据,对于一些复合类型数据,也要满足地址对齐要求。
  7.2结构体的对齐
  结构体作为一种复合数据类型,编译器在给一个结构体变量分配存储空间时,不仅要考虑结构体内各个基本成员的地址对齐,还要考虑结构体整体的对齐。为了结构体内的成员地址对齐,编译器可能会在结构体内填充一些空间;为了结构体整体对齐,编译器可能会在结构体的末尾填充一些空间。
  接下来,我们定义一个结构体,结构体内定义 int、char和 short三种成员,并打印结构体的大小和各个成员的地址。
  structdata{
  chara;
  intb;
  shortc;
  }
  intmain(void)
  {
  structdatas;
  printf("size:%d ",sizeof(s));
  printf("a:%p ",&s.a);
  printf("b:%p ",&s.b);
  printf("c:%p ",&s.c);
  }
  程序运行结果如下。
  size: 12
  &s.a: 0028FF30
  &s.b: 0028FF34
  &s.c: 0028FF38
  我们可以看到,因为结构体的成员 b需要4字节对齐,编译器在给成员 a分配完空间后,接着会空出3个字节,在满足4字节对齐的 0x0028FF34地址处才给成员 b分配存储空间。接着是 short类型的成员 c占据2字节的存储空间。三个结构体成员一共占据4+4+2=10字节的存储空间,根据结构体的对齐规则,结构体的整体对齐要向结构体所有成员中最大对齐字节数或其整数倍对齐,或者说结构体的整体长度要为其最大成员字节数的整数倍,如果不是整数倍要补齐。因为结构体最大成员 int为4个字节,或者说按4字节的整数倍对齐,所以结构体的长度要为4的整数倍,要在结构体的末尾补充2个字节,所以最后结构体的 size为12个字节。
  结构体成员中,不同的排放顺序,可能也会导致结构体的整体长度不一样,我们修改一下上面的程序。
  structdata{
  chara;
  shortb;
  intc;
  };
  intmain(void)
  {
  structdatas;
  printf("size: %d ",sizeof(s));
  printf("&s.a: %p ",&s.a);
  printf("&s.b: %p ",&s.b);
  printf("&s.c: %p ",&s.c);
  }
  程序运行结果如下。
  size:8
  &s.a:0028FF30
  &s.b:0028FF32
  &s.c:0028FF34
  我们调整了一些成员顺序,你会发现,char型变量 a和 short型变量b,分配在了结构体的前4个字节存储空间中,而且都满足各自的地址对齐,整个结构体大小是8字节,只造成一个字节的内存空洞。我们继续修改程序,让 short型的变量 b按4字节对齐:
  structdata{
  chara;
  shortb__attribute__((aligned(4)));
  intc;
  };
  程序运行结果如下。
  size:12
  &s.a:0028FF30
  &s.b:0028FF34
  &s.c:0028FF38
  你会发现,结构体的大小又重新变为12个字节。这是因为,我们显式指定 short变量以4字节地址对齐,导致变量 a的后面填充了3个字节空间。int型变量 c也要4字节对齐,所以变量 b的后面也填充了2个字节,导致整个结构体的大小为12字节。
  我们不仅可以显式指定结构体内某个成员的地址对齐,也可以指定整个结构体的对齐方式。
  structdata{
  chara;
  shortb;
  intc;
  }__attribute__((aligned(16)));
  程序运行结果如下。
  size:16
  &s.a:0028FF30
  &s.b:0028FF32
  &s.c:0028FF34
  在这个结构体中,各个成员一共占8个字节。通过前面学习我们知道,整个结构体的对齐只要是最大成员对齐字节数的整数倍即可。所以这个结构体整体就以8字节对齐,结构体的整体长度为8字节。但是我们在这里,显式指定结构体整体以16字节对齐,所以编译器就会在这个结构体的末尾填充8个字节以满足16字节对齐的要求,导致结构体的总长度变为16字节。
  7.3思考:编译器一定会按照我们指定的大小对齐吗?
  通过 aligned属性,我们可以显式指定一个变量的对齐方式,那么,编译器就一定会按照我们指定的大小对齐吗?非也!
  我们通过这个属性声明,其实只是建议编译器按照这种大小地址对齐,但不能超过编译器允许的最大值。一个编译器,对每个基本数据类型,都有默认的最大边界对齐字节数。如果你超过了,不好意思,我不奉陪,编译器只能按照它规定的最大对齐来给你的变量分配地址。
  charc1=3;
  charc2__attribute__((aligned(16)))=4;
  intmain(void)
  {
  printf("c1:%p ",&c1);
  printf("c2:%p ",&c2);
  return0;
  }
  在这个程序中,我们指定 char型的变量 c2以16字节对齐,然后运行结果为:
  c1:00402000c2:00402010
  我们可以看到,编译器给 c2分配的地址就是16字节地址对齐的,如果我们继续修改 c2变量按32字节对齐,你会发现程序的运行结果不再会有变化,编译器还会分配一个16字节对齐的地址,因为已经超过编译器允许的最大值了。
  7.4属性声明:packed
  aligned属性一般用来增大变量的地址对齐,元素之间因为地址对齐会造成一定的内存空洞。而 packed属性则与之相反,用来减少地址对齐,用来指定变量或类型使用最可能小的地址对齐方式。
  structdata{
  chara;
  shortb__attribute__((packed));
  intc__attribute__((packed));
  };
  intmain(void)
  {
  structdatas;
  printf("size: %d ",sizeof(s));
  printf("&s.a: %p ",&s.a);
  printf("&s.b: %p ",&s.b);
  printf("&s.c: %p ",&s.c);
  }
  在这个程序中,我们将结构体的成员 b和 c使用 packed属性声明,就是告诉编译器,尽量使用最可能小的地址对齐给它们分配地址,尽可能地减少内存空洞。程序的运行结果如下。
  size:7
  &s.a:0028FF30
  &s.b:0028FF31
  &s.c:0028FF33
  通过结果我们看到,结构体内各个成员地址的分配,使用最小1字节的对齐方式,导致整个结构体的大小只有7个字节。
  这个特性在底层驱动开发中还是非常有用的。比如,你想定义一个结构体,封装一个 IP控制器的各种寄存器。在 ARM芯片中,每一个控制器的寄存器地址空间一般是连续存在的。如果考虑数据对齐,结构体内有空洞,这样就跟实际连续的寄存器地址不一致了,使用 packed就可以避免这个问题,结构体的每个成员都紧挨着依次分配存储地址,这样就避免了各个成员元素因地址对齐而造成的内存空洞。
  structdata{
  chara;
  shortb;
  intc;
  }__attribute__((packed));
  我们对整个结构体添加 packed属性,和分别对每个成员添加 packed属性,效果是一样的。修改结构体后,程序的运行结果跟上面程序运行结果相同——结构体的大小为7,结构体内各成员地址相同。
  7.5 Linux内核中 aligned、packed属性声明
  在 Linux内核中,我们经常看到 aligned和 packed一起使用,即对一个变量或类型同时使用 aligned和 packed属性声明。这样做的好处是,既避免了结构体内因地址对齐产生的内存空洞,又指定了整个结构体的对齐方式。
  structdata{
  chara;
  shortb;
  intc;
  }__attribute__((packed,aligned(8)));
  intmain(void)
  {
  structdatas;
  printf("size: %d ",sizeof(s));
  printf("&s.a: %p ",&s.a);
  printf("&s.b: %p ",&s.b);
  printf("&s.c: %p ",&s.c);
  }
  程序运行结果如下。
  size:8
  &s.a:0028FF30
  &s.b:0028FF31
  &s.c:0028FF33
  在这个程序中,结构体 data虽然使用 packed属性声明,整个长度变为7,但是我们同时又使用了 aligned(8)指定其按8字节地址对齐,所以编译器要在结构体后面填充1个字节,这样整个结构体的大小就变为8字节,按8字节地址对齐。

变态禁忌病娇让他演的淋漓尽致高启盛不是他最大的成功影视杂谈狂飙看到26集,很难不爱高启盛。除了剧本精彩导演在行外,演员的表演也赋予这个角色很大加成。看完这部剧的花絮,那个挨打都挨的很认真,杀青时候哭到失神的苏小玎是真的很用心的在演这部电影,鲤城出品2月7日晚上,武侠动作电影天龙八部之乔峰传在鲤城开元盛世广场万达影院举办特别观影,影片监制王晶总出品人朱玮杰等出席,并与观众互动交流,现场气氛格外热烈。据悉,影片改编自金庸武侠小说潘粤明想你跟作死有区别吗有网友扒出董洁跟潘粤明的社交账号,发现一切互动有迹可循去年8月的时候董洁发了韭菜饺子的照片,同月潘粤明也发出来同款董洁某书都是做饭的视频顺便捋下整个事件的时间线2005年8月,潘粤我的小孩来了,言承旭道歉!2月8日中午,沉寂许久的演员言承旭通过社交平台发文称我的小孩来了文尾还配了一个爱心的表情。由于此前也有艺人突然官宣结婚或生子的消息,网友纷纷猜测难道46岁的言承旭也突然有孩子了吗?轮到美国着急了!100国产芯生产线问世,性能提升1000倍传统芯片还能发展多久?现如今台积电,三星已实现3nm量产,并计划在2025年量产2nm。但是到了1nm及以下,传统制程的芯片工艺估计很难创造新的工艺成就。美国大多数的芯片技术集中在pikachu靶场之RCE命令执行RCE(remotecommandcodeexecute)可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。1远程系统命令执行一般出现这种漏洞,是因为应用林建华参与研发全球首颗二维码解码芯片在超市购物,人们只需亮出付款条码,收银员用扫描枪轻轻一扫,就能完成付款。这其中,二维码识读技术至关重要。二维码解码中国芯从无到有,新大陆科技集团的条码识读技术专家林建华是见证者,更加拿大皇家骑警选择特斯拉ModelY作为首辆全电动警车IT之家2月9日消息,根据CTVNews报道,加拿大皇家骑警(RCMP)宣布选择特斯拉的ModelY作为首辆全电动警车,未来将会在温哥华岛南部投入使用。RCMP表示根据2020年的春天吃3草,不把医生找,现在吃正当季,六种做法收藏好大家好这里是香姐做美食,每天分享好吃的家常菜。春天到了,万物复苏,到处充满了生长的气息,田间地头的野菜也开始冒出来了,这是大自然的馈赠。春天的野菜,懂吃的人都开始去寻来做成美味的美正月一碗汤,不用医生帮!滋补又养胃,全家都健康!年前备年货的时候,鸡鸭鱼肉自然是少不了的,但是有一样食材是我们必须买的,那就是山药。山药不仅百搭,还有很好的保健功效,山药食两用的食物,既能够当做药物来治病,也可以当作主食来食用。65岁的天地女儿杨丽萍不婚不育不吃米饭,年轻时有多惊艳!又自由又洒脱又美丽原生态又充满大自然神性的美有一种神秘感年轻时期民族风的穿搭好时尚好适合她!穿出了随性又高级的感觉随便一个回眸,像个侠女,独立坚定清醒不被世俗和情爱影响,敢爱敢恨,
再见奋斗两年的广西黄慕诗日记昨天看着微信余额的数字还跟友友念念叨叨说,这次辞职一定要玩个够,牛皮刚吹出去心里盘算着工作两年攒下来的那点肉,该如何去作时,闺蜜的圣旨来得猝不及防,急召火速回苏,本想着将在外,君命漫山叠翠茶飘香茶树出新芽。全国名特优新农产品廉江红乌龙茶。茶农抢在清明节前采摘今年头茬春茶。村民正在采茶。加工新茶。筛选茶叶。茶叶种植基地一派忙碌景象。又到春茶上市时。沉寂了一个冬天后,廉江近4冬季护心正当时,除防寒保暖外,这些药膳可以试一试进入三九以后,一些老年人因骤然降温导致血压升高,甚至引发心脏不适。那么,寒冷的冬季该如何科学保护心脏?心脏五行属火,是一个喜欢温暖的脏器,冬天气温较低,原本体质较弱的人群,老年人尤狗尾巴草是个宝?用来煮水喝,或许能帮助解决这6个问题狗尾巴草很普通,路边的草丛里,路边的草丛里,农田里的草丛里,到处都是它的影子。狗尾巴草是一种中药,具有清热解毒的功效,对于一些疑难杂症也有一定的疗效。一些注重养生的人,在日常生活中经常腿抽筋,是咋回事?柯大夫,您好。最近,我的腿经常抽筋,把我疼到不行,揉了很久也没缓解。我想问下,我这是什么导致的,是缺钙吗?家医柯大夫抽筋在医学上被称为肌肉痉挛,一般会维持数秒或数十秒。缺钙是腿抽筋中招桃花癣?专家教你这样应对春季过敏七宗罪隆冬过去,春回大地,万物复苏,生机盎然,殊不知,恼人的皮肤病也悄然来袭,可谓皮疾知时节,当春乃发生。每当春天来临时,皮肤特别是颜面部就会干燥出现红斑丘疹脱皮伴有不同程度的瘙痒,严重兰州人与牛肉面兰州有很多标签,但最深入人心的当属兰州牛肉面。兰州牛肉面在中国家喻户晓,在世界上也是有名的特色面食。没到过兰州的人应该也都吃过兰州牛肉面。来兰州看不看黄河,逛不逛兰州大学都无关紧要买酒不要嫌弃包装,包装精美的酒不一定是好酒,简陋包装也有好酒买酒不要嫌弃包装,包装精美的酒不一定是好酒,简陋包装也有好酒。这句话在酒类行业中已经成为了一个共识。但是,在我们购买酒类产品的时候,仍然会被包装的华丽和精美所吸引,而忽略了酒本身的出现四种情况,要警惕糖尿病糖尿病是指在血糖长期升高的基础上,体内糖代谢处于失控状态。这时,体内各脏器和外周组织糖利用能力和胰腺分泌胰岛素控制血糖功能下降,血糖维持高水平,产生一系列症状和造成重要器官的损害。14岁小嫚体重达170斤一查竟是糖尿病来源半岛都市报半岛网3月28日讯(记者孙贴静通讯员毕乙贺)近日,14岁的女孩丽丽(化名)被查出了糖尿病。家长不禁纳闷孩子那么小怎么会得这种病?丽丽是一名初中生,体重有170斤,BM预防糖尿病足病这些注意事项需要知道人的一生中,双足走的路,大约等于环绕地球5圈,无论是足部皮肤肌肉肌腱筋膜出现问题,患者在活动甚至休息时会有不适的感觉,会大大降低患者生活质量和劳动能力,甚至致残。作为糖尿病患者要明