搜索
bottom↓
回复: 16

寻问指针地址运算与指针所指向数据类型疑问

[复制链接]

出0入0汤圆

发表于 2014-5-11 09:54:11 | 显示全部楼层 |阅读模式
本帖最后由 slzm40 于 2014-5-11 16:53 编辑

        先前在人家C语言上看到代码.很是不理解,下面是人家的原源码的部份.是关于结构体,它定义一结构构如下
这里说明下.uint是无符号16位.uchar无符号8位

我的目的是要在每一次循环把结构体里的变量减1(当变量不为0时)

  1. typedef struct {
  2.         uint tmledval;
  3.         uint tmkeysrval;
  4.         uint tmled1sval;
  5.         uint tmscreemval;
  6.         uint tmalarmval;
  7.         uint tmtempval;
  8. } Soft_Timer;
复制代码

又定义结构体变量
  1. Soft_Timer TM;
复制代码


下面为代码1式(这个是原源码写的)
  1. void tmcontrol()
  2. {
  3.   uchar *p;
  4.   for(p=(uchar *)&TM;p<(uchar *)((uchar *)&TM+sizeof(TM));p++)
  5.         { if (*p>0) (*p)--; }
  6. }
复制代码


下面为代码2式(这个是我为了测试改的)
  1. void tmcontrol()
  2. {
  3.   uint *p;
  4.   for(p=(unsigned int*)&TM;p<(unsigned int *)((unsigned int*)&TM+sizeof(TM));p++)
  5.         { if (*p>0) (*p)--; }
  6.                  }       
  7. }
复制代码


在1式中,对于指针uchar *p表式不理解,在for循环里,这P++每次只对地址加1运算.但是我看结构体里是uint型的.总觉得不对. 于是我改了2式. 这个原源码人家用了很久了..也不会有什么错.有高人出来解答下疑惑.

于是我在汇编里面看汇编原码.可以看下.
原源码1式汇编
  1.     35: for(p=((uchar *)&TM;p<((uchar *)(((uchar *)&TM+sizeof(TM));p++)

  2.         //这里是p=((uchar *)&TM
  3. C:0x0FFE    753B00   MOV      0x3B,#0x00
  4. C:0x1001    753C00   MOV      0x3C,#0x00
  5. C:0x1004    753D4B   MOV      0x3D,#TM(0x4B)
  6.         //这里是p<((uchar  *)(((uchar *)&TM+sizeof(TM))
  7. C:0x1007    C3       CLR      C
  8. C:0x1008    900057   MOV      DPTR,#IRcount(0x0057)
  9. C:0x100B    E53D     MOV      A,0x3D
  10. C:0x100D    9582     SUBB     A,DPL(0x82)
  11. C:0x100F    E53C     MOV      A,0x3C
  12. C:0x1011    9583     SUBB     A,DPH(0x83)
  13. C:0x1013    5020     JNC      C:1035
  14.     36: { if (*p>0) (*p)--; }
  15.         //这里是{ if (*p>0) (*p)--; }
  16. C:0x1015    AB3B     MOV      R3,0x3B
  17. C:0x1017    AA3C     MOV      R2,0x3C
  18. C:0x1019    A93D     MOV      R1,0x3D
  19. C:0x101B    120B92   LCALL    C?CLDPTR(C:0B92)
  20. C:0x101E    D3       SETB     C
  21. C:0x101F    9400     SUBB     A,#0x00
  22. C:0x1021    4005     JC       C:1028
  23. C:0x1023    74FF     MOV      A,#0xFF
  24. C:0x1025    120BD8   LCALL    C?CILDPTR(C:0BD8)
  25.         //这里才是P++
  26. C:0x1028    7401     MOV      A,#0x01
  27. C:0x102A    253D     ADD      A,0x3D
  28. C:0x102C    F53D     MOV      0x3D,A
  29. C:0x102E    E4       CLR      A
  30. C:0x102F    353C     ADDC     A,0x3C
  31. C:0x1031    F53C     MOV      0x3C,A
  32. C:0x1033    80D2     SJMP     C:1007
  33.     37:    }   
  34.    
  35. C:0x1035    22       RET  
复制代码


改后2式汇编
  1.     35: for(p=(uint*)&TM;p<(uint *)((uint*)&TM+sizeof(TM));p++)
  2.         //这里是p=(unsigned char*)&TM
  3. C:0x1055    753B00   MOV      0x3B,#0x00
  4. C:0x1058    753C00   MOV      0x3C,#0x00
  5. C:0x105B    753D4B   MOV      0x3D,#TM(0x4B)
  6.         //这里是p<((uint *)(((uint *)&TM+sizeof(TM))
  7. C:0x105E    C3       CLR      C
  8. C:0x105F    900063   MOV      DPTR,#0x0063
  9. C:0x1062    E53D     MOV      A,0x3D
  10. C:0x1064    9582     SUBB     A,DPL(0x82)
  11. C:0x1066    E53C     MOV      A,0x3C
  12. C:0x1068    9583     SUBB     A,DPH(0x83)
  13. C:0x106A    5026     JNC      C:1092
  14.     36:   { if (*p>0) (*p)--; }
  15.         //这里是{ if (*p>0) (*p)--; }
  16. C:0x106C    AB3B     MOV      R3,0x3B
  17. C:0x106E    AA3C     MOV      R2,0x3C
  18. C:0x1070    A93D     MOV      R1,0x3D
  19. C:0x1072    120940   LCALL    C?ILDPTR(C:0940)
  20. C:0x1075    D3       SETB     C
  21. C:0x1076    9400     SUBB     A,#0x00
  22. C:0x1078    E5F0     MOV      A,B(0xF0)
  23. C:0x107A    9400     SUBB     A,#0x00
  24. C:0x107C    4007     JC       C:1085
  25. C:0x107E    74FF     MOV      A,#0xFF
  26. C:0x1080    F5F0     MOV      B(0xF0),A
  27. C:0x1082    12096B   LCALL    C?IILDPTR(C:096B)
  28.         //这里才是P++
  29. C:0x1085    7402     MOV      A,#0x02
  30. C:0x1087    253D     ADD      A,0x3D
  31. C:0x1089    F53D     MOV      0x3D,A
  32. C:0x108B    E4       CLR      A
  33. C:0x108C    353C     ADDC     A,0x3C
  34. C:0x108E    F53C     MOV      0x3C,A
  35. C:0x1090    80CC     SJMP     C:105E
  36.     37:                  }      
  37. C:0x1092    22       RET   
复制代码

/**********************************以下算是结贴部份***有错误指出,我再修正,第一次在结构体操作指针,当然我的指针方面运用很一般**********/

对于1式,其实没有错.因为结构体里面的数据,初始化时都右移8位过.也就是说.所有数据高8位都为零.也就是不会作减1操作.相当于只操作低8位. 达到每个数据都减1. 这个源码是以前一个工程师写的,用在软时基.

关于式2,我改的.经过论坛的高位指错,也领悟了一些.现将式子改为如下.

  1. void tmcontrol()
  2. {
  3.   uint *p;
  4.   for(p=(uint *)&TM;p<(uint *)((uchar  *)&TM+sizeof(TM));p++)

  5.         { if (*p>0) (*p)--; }

  6. }
复制代码


式2的汇编部份我也弄出来

  1.     35: for(p=(unsigned int*)&TM;p<(unsigned int *)((unsigned char*)&TM+sizeof(TM));p++)
  2.         //这里是p=(unsigned int*)&TM
  3. C:0x1055    753B00   MOV      0x3B,#0x00
  4. C:0x1058    753C00   MOV      0x3C,#0x00
  5. C:0x105B    753D4B   MOV      0x3D,#TM(0x4B)
  6.         //这里是p<(unsigned int *)((unsigned char*)&TM+sizeof(TM))
  7. C:0x105E    C3       CLR      C
  8. C:0x105F    900057   MOV      DPTR,#IRcount(0x0057)
  9. C:0x1062    E53D     MOV      A,0x3D
  10. C:0x1064    9582     SUBB     A,DPL(0x82)
  11. C:0x1066    E53C     MOV      A,0x3C
  12. C:0x1068    9583     SUBB     A,DPH(0x83)
  13. C:0x106A    5026     JNC      C:1092
  14.     36:  { if (*p>0) (*p)--; }
  15. C:0x106C    AB3B     MOV      R3,0x3B
  16. C:0x106E    AA3C     MOV      R2,0x3C
  17. C:0x1070    A93D     MOV      R1,0x3D
  18. C:0x1072    120940   LCALL    C?ILDPTR(C:0940)
  19. C:0x1075    D3       SETB     C
  20. C:0x1076    9400     SUBB     A,#0x00
  21. C:0x1078    E5F0     MOV      A,B(0xF0)
  22. C:0x107A    9400     SUBB     A,#0x00
  23. C:0x107C    4007     JC       C:1085
  24. C:0x107E    74FF     MOV      A,#0xFF
  25. C:0x1080    F5F0     MOV      B(0xF0),A
  26. C:0x1082    12096B   LCALL    C?IILDPTR(C:096B)
  27.         //这里才是P++
  28. C:0x1085    7402     MOV      A,#0x02
  29. C:0x1087    253D     ADD      A,0x3D
  30. C:0x1089    F53D     MOV      0x3D,A
  31. C:0x108B    E4       CLR      A
  32. C:0x108C    353C     ADDC     A,0x3C
  33. C:0x108E    F53C     MOV      0x3C,A
  34. C:0x1090    80CC     SJMP     C:105E
  35.     37:                  }      
  36. C:0x1092    22       RET  
复制代码


有什么错误欢迎指正. 不知道我写的对不对.

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2014-5-11 10:00:09 | 显示全部楼层
声明下.我的MCU是8位的.

出0入0汤圆

发表于 2014-5-11 10:09:22 | 显示全部楼层
我觉得第一个有问题

出0入0汤圆

 楼主| 发表于 2014-5-11 10:18:41 | 显示全部楼层
qq302011 发表于 2014-5-11 10:09
我觉得第一个有问题

好吧..我又仔细看了程序,,1式按理来说.的确是有问题的....但是写程序的这个人...竟然把结构体的变量在初始化后,对每个变量还右移8位...这样..这个式子就不会错了.因为高8位一直是零.  
还是用2式,自己写的保险一点

出0入0汤圆

发表于 2014-5-11 10:25:58 | 显示全部楼层
什么叫“原源码人家用了很久了..也不会有什么错”

出0入93汤圆

发表于 2014-5-11 10:46:07 | 显示全部楼层
1、{}个数都不匹配,无法通过编译。
2、第一个:一个uint类型的高字节和低字节都发生了改变,出现逻辑错误。
3、第二个:p<(unsigned int *)((unsigned int*)&TM+sizeof(TM))出现缓冲区溢出错误,程序跑飞是非常正常的。

出0入0汤圆

发表于 2014-5-11 10:56:06 | 显示全部楼层
slzm40 发表于 2014-5-11 10:18
好吧..我又仔细看了程序,,1式按理来说.的确是有问题的....但是写程序的这个人...竟然把结构 ...

第一个式子,结构体中的每个变量即使右移了8位后再减一也是错的呀,这样是每个变量的高位减一,不是每个变量减一。

出0入0汤圆

发表于 2014-5-11 11:31:04 | 显示全部楼层
个人感觉结构体定义成这样可能是因为内存对齐问题

出0入0汤圆

发表于 2014-5-11 11:52:14 | 显示全部楼层
六楼说的对,第二个式子也有问题。
p<(unsigned int *)((unsigned int*)&TM+sizeof(TM))中的((unsigned int*)&TM+sizeof(TM))可以这样理解:指针变量(unsigned int*)&TM的值加上结构体TM所占的空间大小(注意:结构体TM所占的空间大小以字节为单位),但是指针变量加1后指针变量的值并不一定只是增加了1,比如:指针变量char *p原来p=0x1234,加1后即(p+1)=0x1235;指针变量int *p原来p=0x1234,加1后即(p+1)=0x1236。所以第二个式子循环里指针已经指向了结构体的外部。

出0入0汤圆

 楼主| 发表于 2014-5-11 12:05:38 | 显示全部楼层
hithms 发表于 2014-5-11 11:52
六楼说的对,第二个式子也有问题。
p

1.那个{}不对是我把上面一些程序去掉了.所以出现错误.实际我编译是对的,我程序里面是完整程序.
2.  1式中,高位已经等于0了.就不会再减1操作了.因为右移8位.高位一直是等于0的.也就是说相当于每次只对低8位直接操作. 
3.指针不会指向循环体外.for里有限制. p<(unsigned int *)((unsigned int*)&TM+sizeof(TM))  这里是首地址加上TM的长度(字节数量). 怎么也不会指到外面吧.

出0入224汤圆

发表于 2014-5-11 12:10:07 | 显示全部楼层
slzm40 发表于 2014-5-11 12:05
1.那个{}不对是我把上面一些程序去掉了.所以出现错误.实际我编译是对的,我程序里面是完整程序.
2. ...

怎么不会, sizeof(TM) 得到的是结构占用的字节数.

出0入0汤圆

发表于 2014-5-11 12:16:14 | 显示全部楼层
slzm40 发表于 2014-5-11 12:05
1.那个{}不对是我把上面一些程序去掉了.所以出现错误.实际我编译是对的,我程序里面是完整程序.
2. ...

是不会指到循环体外面,但会指到结构体外面。

出0入0汤圆

 楼主| 发表于 2014-5-11 12:36:38 来自手机 | 显示全部楼层
hithms 发表于 2014-5-11 12:16
是不会指到循环体外面,但会指到结构体外面。

最后一步的确地址会大于结构体地址,但不会执行循环程序,指向结构体外有什么影响,只是在判断,不会执行循环程序。    以前一直用数组实现这个,这次用结构体,果然遇到
很多问题啊。

出0入93汤圆

发表于 2014-5-11 12:47:53 | 显示全部楼层
slzm40 发表于 2014-5-11 12:36
最后一步的确地址会大于结构体地址,但不会执行循环程序,指向结构体外有什么影响,只是在判断,不会执行 ...

LZ,缓冲区溢出是一个非常常见的错误,不仅仅出现在你这里,也不仅仅出现在C/C++语言中,而且出问题了还特别难找。
C语言的指针是一把双刃剑,磨刀恨不利,刀利伤人指啊。
就以你这个代码的第二段为例,你很显然希望for循环执行6次,可是你却执行了sizeof(TM)=12次,这样,TM里面的内容是正确改变了,但是TM后续12个字节的内容也被你误伤了,因此说缓冲区溢出。
正确的写法应该是这样的:
  1. p<(uint*)&TM+sizeof(TM) / sizeof(uint);
复制代码
,或这样
  1. p<(unsigned int *)((unsigned char*)&TM+sizeof(TM));
复制代码
,虽然与你的代码差别不大,但是效果确实完全不一样的。

出0入0汤圆

 楼主| 发表于 2014-5-11 16:00:57 | 显示全部楼层
本帖最后由 slzm40 于 2014-5-11 16:02 编辑
takashiki 发表于 2014-5-11 12:47
LZ,缓冲区溢出是一个非常常见的错误,不仅仅出现在你这里,也不仅仅出现在C/C++语言中,而且出问题了还 ...


这个是这样么? 两段代码.P++是不一样的.1式,是加1,而2式,是加2. 我汇编也贴出了...2式中的P++是每个地址加2的,声明uint *P.

然后p<(unsigned int *)((unsigned int*)&TM+sizeof(TM)); 这段完全是地址比较,不是数量比较.

出0入93汤圆

发表于 2014-5-11 16:16:28 | 显示全部楼层
slzm40 发表于 2014-5-11 16:00
这个是这样么? 两段代码.P++是不一样的.1式,是加1,而2式,是加2. 我汇编也贴出了...2式中的P ...

你既然知道第二段代码的p++是+2,那么你觉得(unsigned int *)((unsigned int*)&TM+sizeof(TM));加的是多少呢?
实际上加的是2*sizeof(TM)啊哥们。自增的你弄明白了,加号的你就犯糊涂了。

出0入0汤圆

 楼主| 发表于 2014-5-11 16:36:54 | 显示全部楼层
takashiki 发表于 2014-5-11 16:16
你既然知道第二段代码的p++是+2,那么你觉得(unsigned int *)((unsigned int*)&TM+sizeof(TM));加的是多 ...

..你这一点,让我明白了.. 第一次在结构体用这样算. 学习了许多啊. 仔细一看汇编.果然是我错了,还是大错特错.果然是2*sizeof(TM).
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 12:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表