免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 10261 | 回复: 22
打印 上一主题 下一主题

[C] 指针类型强转时,奇数地址会产生问题,为什么?[赋详细数据] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-15 14:13 |只看该作者 |倒序浏览
20可用积分
指针类型强转时,奇数地址会产生问题,为什么?[赋详细数据]

/* 要求必须使用(unsigned int *)p来访问,list的类型定义也不能改*/
unsigned int *p1 = NULL;
unsigned int *p2 = NULL;

/*下面访问p2或list[2]没有问题,访问p1或list[1]有问题,为什么?*/

unsigned char  list[64][128*2+1];

address of list[1]==0836eb3d
address of (unsigned int *)list[1]==0836eb3d
address of list[2]==0836ec3e
address of (unsigned int *)list[2]==0836ec3e

p1 = (unsigned int *)list[1];
p2 = (unsigned int *)list[2];

/* 下面访问p1, p2或 list[1], list[2]都没有问题 */

unsigned char  list[64][(128+1)*2];

address of list[1]==0836eb3e
address of (unsigned int *)list[1]==0836eb3e
address of list[2]==0836ec40
address of (unsigned int *)list[2]==0836ec40

p1 = (unsigned int *)list[1];
p2 = (unsigned int *)list[2];

论坛徽章:
0
2 [报告]
发表于 2009-04-15 14:22 |只看该作者
什么叫"奇数地址"???


请给出事例代码和相应的输入输出

论坛徽章:
0
3 [报告]
发表于 2009-04-15 14:31 |只看该作者

回复 #2 net_robber 的帖子

看我的帖子中给出的数据:
list定义:
unsigned char  list[64][128*2+1]; /*! */

address of (unsigned char *)list[1]==0836eb3d
address of (unsigned int *)list[1]==0836eb3d /*按 (unsigned int *)访问list[1]有问题 */

unsigned char  list[64][(128+1)*2];/*不同定义 */

address of (unsigned char *)list[1]==0836eb3d
address of (unsigned int *)list[1]==0836eb3d /*按 (unsigned int *)访问list[1]没有问题 */

论坛徽章:
0
4 [报告]
发表于 2009-04-15 14:36 |只看该作者
可能是编译器对unsigned int*指针的一种字节对齐的优化

有关字节对齐的介绍:
什么是对齐,以及为什么要对齐:
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
对齐的作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
对齐的实现:
通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。
但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。

注意这里:“如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期”同样的编译器可能会对指针类型的变量做一些优化,让它从偶地址开始。

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
5 [报告]
发表于 2009-04-15 14:40 |只看该作者
总线问题,编译的时候用1字节对齐试试

论坛徽章:
0
6 [报告]
发表于 2009-04-15 14:42 |只看该作者
#include <stdio.h>
void main()
{
unsigned char list[64][128*2+1];
unsigned int *p1;
unsigned int *p2;
printf("address of list[1]==[%x]\n", list[1]);
p1 = (unsigned int *)list[1];
printf("address of p1==[%p]\n", p1);
printf("address of list[2]==[%x]\n", list[2]);
p2 = (unsigned int *)list[2];
printf("address of p2==[%p]\n", p2);

}
在sco上测试正常啊,地址一致的
address of list[0]==[7ffffbc8]
address of p1==[7ffffbc8]
address of list[1]==[7ffffbcb]
address of p2==[7ffffbcb]

论坛徽章:
0
7 [报告]
发表于 2009-04-15 14:46 |只看该作者

回复 #6 pflifeshow 的帖子

多个编译器测试,地址都是一致的,
只是访问list[1]和list[2]的时候有差异,list[][]的定义改变也有差异

将list[][]的定义对齐后就不会有问题了,为什么会这样呢?
高手讲解下吧,学习了!为何list[][]的定义不对齐会有问题?

论坛徽章:
0
8 [报告]
发表于 2009-04-15 15:13 |只看该作者
看来一楼还是没看懂我刚才说的东东
如果定义成:
unsigned char list[64][128*2+1];
假设list开始的地址为0x1000;
list[1]即访问list[1][0]=0x1000+128*2+1此地址为奇地址,要对其强行转换成unsigned int*时编译器可能会对其进行优化,编译器可能要求4byte的数据必须以偶地址开始
list[2]即访问list[2][0]=0x1000+128*2+1+128*2+1=0x1000+2*(128*2+1)此地址为偶地址编译器不做优化
如果定义成:
unsigned char  list[64][(128+1)*2];
无论访问list[1]或者list[2]都形如上面的list[2]的形式。。。

[ 本帖最后由 flyingtime 于 2009-4-15 15:20 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2009-04-15 15:27 |只看该作者
address of (unsigned int *)list[1]==0836eb3d /*按 (unsigned int *)访问list[1]有问题 */
上面是运行时,输出的是奇数地址,编译器没有对齐呀!运行时访问这个地址应该也没有问题吧!

“list[1]即访问list[1][0]=0x1000+128*2+1此地址为奇地址,要对其强行转换成unsigned int*时编译器可能会对其进行优化”

能举个例子说明对齐后的地址一个可能的情况吗?俺没弄明白咋计算对其后的地址,呵呵

论坛徽章:
0
10 [报告]
发表于 2009-04-15 15:42 |只看该作者
首先unsigned int* p = (unsigned int*)list[1];
访问的是时候你是用*p吧,编译器可能要求指针所指向的地址开始为偶地址,就会在
unsigned int* p = (unsigned int*)list[1];时强行给p一个偶地址。
关于字节对齐的问题你可以google or baidu 一下,会有很多例子,如
struct test
{
  int x;
  char y;
  int z;
};
这样z的偏移在test中很有可能会变
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP