免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: superwujc
打印 上一主题 下一主题

[C] 烦请哪位老大可以介绍一下C语言中的内存对齐的原理和实现? [复制链接]

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
21 [报告]
发表于 2012-08-29 03:37 |只看该作者
本帖最后由 Ager 于 2012-08-29 04:59 编辑
gvim 发表于 2012-08-29 03:15

64位(bits)

这话扯的


版主大虾看得仔细!赞 —— :)

这种错误我可不敢犯唉……否则就成了“CMate”了。不过,如果我真的犯错的话,那么承担罪过责任和受罚也是应当的,版主大虾做裁判,对于我这个穷光蛋也应该要惩治严明。我虽“扯”也不应当免责遁罚。

那么……等我重新扯一下……把关系表达清楚……

的确怪我,呵呵……



论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
22 [报告]
发表于 2012-08-29 04:14 |只看该作者
gvim 发表于 2012-08-29 02:50
写这么多,也忒认真回复了吧,怎么的也得加8分吧,哈哈。


版主大虾厉害!是应该加分哦 —— 但好像普通用户不能给版友的帖子评分/加分吧,只有版主可以吧?(我想给大虾加分,把我自己的分消耗掉给你都可以呀!但我找不到按钮……)

我在上面把关系式补齐了,不过,这也都是我的扯,还等待大虾验证评判{:3_202:}

论坛徽章:
0
23 [报告]
发表于 2012-08-29 08:55 |只看该作者
都是些什么呀,乱七八糟

论坛徽章:
4
天秤座
日期:2013-10-18 13:58:33金牛座
日期:2013-11-28 16:17:01辰龙
日期:2014-01-14 09:54:32戌狗
日期:2014-01-24 09:23:27
24 [报告]
发表于 2012-08-29 11:09 |只看该作者
本帖最后由 liuiang 于 2012-08-29 11:19 编辑

向楼上学习,顺便也唠叨几句。

针对楼主问题,我不确定是函数原型看不懂还是函数实现代码看不懂,所以胡乱说说。

内存分配会返回一个指针,那么对齐就意味着,返回的指针所指向的空间的访问地址是对齐的,

如果是2字节对齐,那么地址最低1bit一定是0,返回地址一定能被2整除,如果是4字节对齐则最低2 bits一定是0,

返回地址一定能被4整除,如果是16字节对齐则最后4bits一定是0,同样该地址可以被16整除。

原理4楼说的很清楚了,就是预先多分配一些空间,然后将返回的地址根据输入的对齐参数,向后偏移,返回即可。

实现则比较多,有一些也比较复杂,网上搜索了一下,建议你先看malloc的实现:

顺便给个链接参考:http://blog.csdn.net/dog250/article/details/5302958

malloc实现理解之后,对齐malloc其实就是一个简单变形,参考下图:
  1.   p = memalign(16, 100);
  2.        ______
  3.       |      |
  4.       |      |
  5.         ...
  6.       |      |
  7.       |      |
  8.       |      |
  9.   p-> |______| 0x-------0
  10.       |      | 0x-------F
  11.       |      | 0x-------E
  12.       |      | <- 我是一个管理分配出来的内存块的数据结构对象,我不知道我的起始地址应该是多少,
  13.       |______|    但我知道我的结束地址是根据用户参数内存对齐的,比如这个例子俺们是16字节对齐
复制代码
现在楼主主要问题回答基本完成,既然大家都在扯,我也扯扯。

问题是:我们为什么需要对齐的内存?

简单的回答:效率。但根本原因是----硬件。反过来说,如果一个处理器或者一个硬件设备,他“可以”访问所有的

地址空间而不管地址是否是对齐的,并且效率完全都是一样的,那么我们可以认为,在这样的系统中,是不需要

专门进行对齐操作。但事实上这种假设在现代计算机系统中基本上是不成立的,主要包括:

1,硬件设备在进行DMA或者其他访问操作的时候,需要cache对齐或者page对齐,典型的是应用程序希望对IO设备
   进行直接操作的时候,会采用O_DIRECT选项,事实上是希望系统进行零拷贝,那么对于读写的buf就需要进行
   对齐操作,以方便硬件的访问。大部分的外设对内存对齐都会有不同程度的要求,嵌入式领域的SOC要求
   格外多。

2,Cache的对齐,楼上大侠们见解都很独到,这里不再罗嗦

3,Cpu本身访问数据的对齐要求。这里包含两个方面:

     第一是有些低端处理器,为了降低复杂度和功耗,设计的时候就需要程序指令对内存的访问必须遵循某些
         对齐要求,比如一些ARM或者MIPS。很多人觉得支持不对齐访问是个很简单的事情,其实不然,如果不对齐
         访问跨cache line,那么处理器需要同时处理器两个cache line的状态,同样推而广之,如果访存指令
         针对的地址跨了page,那么TLB要同时处理器两个page,相关问题可以对照楼上一些讨论编译器,数据类型,
         相关的论述查资料理解,这里也不展开了。

     第二是即使一些处理器支持不对齐访问,但仍旧有一些特殊指令对对齐有限制,典型的是原子指令,如x86下的
         CMPXCHG8B/16B,另外多媒体指令为了提升性能,也有一些有限制,这些都与cache和总线相关,
         这里也不展开了。

可能还有一些遗漏,希望有人可以补充。

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
25 [报告]
发表于 2012-08-29 12:14 |只看该作者
liuiang 发表于 2012-08-29 11:09
向楼上学习,顺便也唠叨几句。

针对楼主问题,我不确定是函数原型看不懂还是函数实现代码看不懂,所以胡 ...


支持!赞:)

论坛徽章:
4
天秤座
日期:2013-10-18 13:58:33金牛座
日期:2013-11-28 16:17:01辰龙
日期:2014-01-14 09:54:32戌狗
日期:2014-01-24 09:23:27
26 [报告]
发表于 2012-08-29 12:39 |只看该作者
其实我只是路过打酱油的。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
27 [报告]
发表于 2012-08-29 15:29 |只看该作者
回复 25# Ager

感谢斑竹lenky0401和gvim老大,Ager大虾,file3,liuiang以及所有楼上大牛

真想不到这么具体的问题竟然可以如此形而上。。。。

感慨万千,不说了。。


   

论坛徽章:
0
28 [报告]
发表于 2012-08-29 23:16 |只看该作者
秘密在于,不同部分对内存“原子单元”的看法不同。

从指令上看,内存基本可寻址单位是byte,然后可以拼出多byte的内存。

从CPU与内存接口上看(不太确定),内存基本可寻址单位(一般)是寄存器长度,比如32bit x86,前端总线的寻址单位是4byte。地址总线的低位根本没有跟内存控制器相连,发过去的地址是说第addr个4byte。如果一个4byte时跨了4byte的边界,从指令上看,这应该是一次正常的内存操作;从硬件接口上看,它必需拆成两次。地址总线上发出去的信号无法描述这种请求。

从cache上看,基本可寻址单位是cache line。原理同上。一般只有操作系统关心这一级别上的对齐。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
29 [报告]
发表于 2012-08-30 00:14 |只看该作者
回复 25# Ager

请问字节填充的规则是怎样的呢?网上说法不一,自己用程序验证如下

编译器类型和系统版本:
  1. root@c-dev:~# gcc --version
  2. gcc (Debian 4.4.5-8) 4.4.5

  3. root@c-dev:/c/tlpi# uname -r
  4. 2.6.32-5-amd64
复制代码
基本数据类型长度:data_type_length.c
  1. #include <stdio.h>

  2. #define LENGTH(x)\
  3. printf(""#x" length as byte: %d\n", (sizeof (x)))

  4. int main (void)
  5. {
  6.     LENGTH(char);
  7.     LENGTH(int);
  8.     LENGTH(short);
  9.     LENGTH(long);
  10.     LENGTH(float);
  11.     LENGTH(double);
  12.     LENGTH(long double);
  13.     LENGTH(void*);

  14.     return 0;
  15. }
复制代码
编译运行,
  1. root@c-dev:/c/tlpi# gcc data_type_length.c -o data_type_length
  2. root@c-dev:/c/tlpi#
  3. root@c-dev:/c/tlpi# data_type_length
  4. char length as byte: 1
  5. int length as byte: 4
  6. short length as byte: 2
  7. long length as byte: 8
  8. float length as byte: 4
  9. double length as byte: 8
  10. long double length as byte: 16
  11. void* length as byte: 8
复制代码
验证代码,align_mem1.c
  1. #include <stdio.h>
  2. #include <stddef.h>

  3. int main (void)
  4. {
  5.     struct MixedData
  6.     {   
  7.         char a;
  8.         short b;
  9.         int c;
  10.         long d;

  11.         /*  
  12.         short a;
  13.         int b;
  14.         char c;
  15.         long d;
  16.         */
  17.     };  

  18.     struct MixedData data0;
  19.     struct MixedData * pt;

  20.     printf ("The addresses:\n");
  21.     printf ("pt = %p,\n&(pt->a) = %p,\n\
  22. &(pt->b) = %p,\n&(pt->c) = %p,\n&(pt->d) = %p.\n",\
  23.     pt, &(pt->a), &(pt->b), &(pt->c), &(pt->d));

  24.     printf ("\n");
  25.     printf ("offsets: a = %d, b = %d, c = %d and d = %d\n",\
  26.     offsetof (struct MixedData, a), offsetof (struct MixedData, b),\
  27.     offsetof (struct MixedData, c), offsetof (struct MixedData, d));

  28.     printf ("\n");
  29.     printf ("The instance data0\'s length as byte: %d\n", sizeof (data0));

  30.     return 0;
  31. }
复制代码
编译运行,结构成员以降序排列
  1. root@c-dev:/c/tlpi/iobuf# align_mem1
  2. The addresses:
  3. pt = 0x4004a0,
  4. &(pt->a) = 0x4004a0,
  5. &(pt->b) = 0x4004a2,
  6. &(pt->c) = 0x4004a4,
  7. &(pt->d) = 0x4004a8.

  8. offsets: a = 0, b = 2, c = 4 and d = 8

  9. The instance data0's length as byte: 16

复制代码
但是结构成员的顺序会导致结果不同,打乱顺序后,
  1. The addresses:
  2. pt = 0x4004a0,
  3. &(pt->a) = 0x4004a0,
  4. &(pt->b) = 0x4004a4,
  5. &(pt->c) = 0x4004a8,
  6. &(pt->d) = 0x4004b0.

  7. offsets: a = 0, b = 4, c = 8 and d = 16

  8. The instance data0's length as byte: 24
复制代码
请问结构成员(推广到复合数据结构)的成员数据项间是按照怎样的规则来填充字节的呢?

论坛徽章:
0
30 [报告]
发表于 2012-08-30 15:16 |只看该作者
你这个是结构体对齐,不一样的 。回复 6# _Rayx


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP