寻问指针地址运算与指针所指向数据类型疑问
本帖最后由 slzm40 于 2014-5-11 16:53 编辑先前在人家C语言上看到代码.很是不理解,下面是人家的原源码的部份.是关于结构体,它定义一结构构如下
这里说明下.uint是无符号16位.uchar无符号8位
我的目的是要在每一次循环把结构体里的变量减1(当变量不为0时)
typedef struct {
uint tmledval;
uint tmkeysrval;
uint tmled1sval;
uint tmscreemval;
uint tmalarmval;
uint tmtempval;
} Soft_Timer;
又定义结构体变量
Soft_Timer TM;
下面为代码1式(这个是原源码写的)
void tmcontrol()
{
uchar *p;
for(p=(uchar *)&TM;p<(uchar *)((uchar *)&TM+sizeof(TM));p++)
{ if (*p>0) (*p)--; }
}
下面为代码2式(这个是我为了测试改的)
void tmcontrol()
{
uint *p;
for(p=(unsigned int*)&TM;p<(unsigned int *)((unsigned int*)&TM+sizeof(TM));p++)
{ if (*p>0) (*p)--; }
}
}
在1式中,对于指针uchar *p表式不理解,在for循环里,这P++每次只对地址加1运算.但是我看结构体里是uint型的.总觉得不对. 于是我改了2式. 这个原源码人家用了很久了..也不会有什么错.有高人出来解答下疑惑.
于是我在汇编里面看汇编原码.可以看下.
原源码1式汇编
35: for(p=((uchar *)&TM;p<((uchar *)(((uchar *)&TM+sizeof(TM));p++)
//这里是p=((uchar *)&TM
C:0x0FFE 753B00 MOV 0x3B,#0x00
C:0x1001 753C00 MOV 0x3C,#0x00
C:0x1004 753D4B MOV 0x3D,#TM(0x4B)
//这里是p<((uchar*)(((uchar *)&TM+sizeof(TM))
C:0x1007 C3 CLR C
C:0x1008 900057 MOV DPTR,#IRcount(0x0057)
C:0x100B E53D MOV A,0x3D
C:0x100D 9582 SUBB A,DPL(0x82)
C:0x100F E53C MOV A,0x3C
C:0x1011 9583 SUBB A,DPH(0x83)
C:0x1013 5020 JNC C:1035
36: { if (*p>0) (*p)--; }
//这里是{ if (*p>0) (*p)--; }
C:0x1015 AB3B MOV R3,0x3B
C:0x1017 AA3C MOV R2,0x3C
C:0x1019 A93D MOV R1,0x3D
C:0x101B 120B92 LCALL C?CLDPTR(C:0B92)
C:0x101E D3 SETB C
C:0x101F 9400 SUBB A,#0x00
C:0x1021 4005 JC C:1028
C:0x1023 74FF MOV A,#0xFF
C:0x1025 120BD8 LCALL C?CILDPTR(C:0BD8)
//这里才是P++
C:0x1028 7401 MOV A,#0x01
C:0x102A 253D ADD A,0x3D
C:0x102C F53D MOV 0x3D,A
C:0x102E E4 CLR A
C:0x102F 353C ADDC A,0x3C
C:0x1031 F53C MOV 0x3C,A
C:0x1033 80D2 SJMP C:1007
37: }
C:0x1035 22 RET
改后2式汇编
35: for(p=(uint*)&TM;p<(uint *)((uint*)&TM+sizeof(TM));p++)
//这里是p=(unsigned char*)&TM
C:0x1055 753B00 MOV 0x3B,#0x00
C:0x1058 753C00 MOV 0x3C,#0x00
C:0x105B 753D4B MOV 0x3D,#TM(0x4B)
//这里是p<((uint *)(((uint *)&TM+sizeof(TM))
C:0x105E C3 CLR C
C:0x105F 900063 MOV DPTR,#0x0063
C:0x1062 E53D MOV A,0x3D
C:0x1064 9582 SUBB A,DPL(0x82)
C:0x1066 E53C MOV A,0x3C
C:0x1068 9583 SUBB A,DPH(0x83)
C:0x106A 5026 JNC C:1092
36: { if (*p>0) (*p)--; }
//这里是{ if (*p>0) (*p)--; }
C:0x106C AB3B MOV R3,0x3B
C:0x106E AA3C MOV R2,0x3C
C:0x1070 A93D MOV R1,0x3D
C:0x1072 120940 LCALL C?ILDPTR(C:0940)
C:0x1075 D3 SETB C
C:0x1076 9400 SUBB A,#0x00
C:0x1078 E5F0 MOV A,B(0xF0)
C:0x107A 9400 SUBB A,#0x00
C:0x107C 4007 JC C:1085
C:0x107E 74FF MOV A,#0xFF
C:0x1080 F5F0 MOV B(0xF0),A
C:0x1082 12096B LCALL C?IILDPTR(C:096B)
//这里才是P++
C:0x1085 7402 MOV A,#0x02
C:0x1087 253D ADD A,0x3D
C:0x1089 F53D MOV 0x3D,A
C:0x108B E4 CLR A
C:0x108C 353C ADDC A,0x3C
C:0x108E F53C MOV 0x3C,A
C:0x1090 80CC SJMP C:105E
37: }
C:0x1092 22 RET
/**********************************以下算是结贴部份***有错误指出,我再修正,第一次在结构体操作指针,当然我的指针方面运用很一般**********/
对于1式,其实没有错.因为结构体里面的数据,初始化时都右移8位过.也就是说.所有数据高8位都为零.也就是不会作减1操作.相当于只操作低8位. 达到每个数据都减1. 这个源码是以前一个工程师写的,用在软时基.
关于式2,我改的.经过论坛的高位指错,也领悟了一些.现将式子改为如下.
void tmcontrol()
{
uint *p;
for(p=(uint *)&TM;p<(uint *)((uchar*)&TM+sizeof(TM));p++)
{ if (*p>0) (*p)--; }
}
式2的汇编部份我也弄出来
35: for(p=(unsigned int*)&TM;p<(unsigned int *)((unsigned char*)&TM+sizeof(TM));p++)
//这里是p=(unsigned int*)&TM
C:0x1055 753B00 MOV 0x3B,#0x00
C:0x1058 753C00 MOV 0x3C,#0x00
C:0x105B 753D4B MOV 0x3D,#TM(0x4B)
//这里是p<(unsigned int *)((unsigned char*)&TM+sizeof(TM))
C:0x105E C3 CLR C
C:0x105F 900057 MOV DPTR,#IRcount(0x0057)
C:0x1062 E53D MOV A,0x3D
C:0x1064 9582 SUBB A,DPL(0x82)
C:0x1066 E53C MOV A,0x3C
C:0x1068 9583 SUBB A,DPH(0x83)
C:0x106A 5026 JNC C:1092
36:{ if (*p>0) (*p)--; }
C:0x106C AB3B MOV R3,0x3B
C:0x106E AA3C MOV R2,0x3C
C:0x1070 A93D MOV R1,0x3D
C:0x1072 120940 LCALL C?ILDPTR(C:0940)
C:0x1075 D3 SETB C
C:0x1076 9400 SUBB A,#0x00
C:0x1078 E5F0 MOV A,B(0xF0)
C:0x107A 9400 SUBB A,#0x00
C:0x107C 4007 JC C:1085
C:0x107E 74FF MOV A,#0xFF
C:0x1080 F5F0 MOV B(0xF0),A
C:0x1082 12096B LCALL C?IILDPTR(C:096B)
//这里才是P++
C:0x1085 7402 MOV A,#0x02
C:0x1087 253D ADD A,0x3D
C:0x1089 F53D MOV 0x3D,A
C:0x108B E4 CLR A
C:0x108C 353C ADDC A,0x3C
C:0x108E F53C MOV 0x3C,A
C:0x1090 80CC SJMP C:105E
37: }
C:0x1092 22 RET
有什么错误欢迎指正. 不知道我写的对不对.
声明下.我的MCU是8位的. 我觉得第一个有问题 qq302011 发表于 2014-5-11 10:09
我觉得第一个有问题
好吧..我又仔细看了程序,,1式按理来说.的确是有问题的....但是写程序的这个人...竟然把结构体的变量在初始化后,对每个变量还右移8位...这样..这个式子就不会错了.因为高8位一直是零.
还是用2式,自己写的保险一点 什么叫“原源码人家用了很久了..也不会有什么错” 1、{}个数都不匹配,无法通过编译。
2、第一个:一个uint类型的高字节和低字节都发生了改变,出现逻辑错误。
3、第二个:p<(unsigned int *)((unsigned int*)&TM+sizeof(TM))出现缓冲区溢出错误,程序跑飞是非常正常的。 slzm40 发表于 2014-5-11 10:18
好吧..我又仔细看了程序,,1式按理来说.的确是有问题的....但是写程序的这个人...竟然把结构 ...
第一个式子,结构体中的每个变量即使右移了8位后再减一也是错的呀,这样是每个变量的高位减一,不是每个变量减一。 个人感觉结构体定义成这样可能是因为内存对齐问题 六楼说的对,第二个式子也有问题。
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。所以第二个式子循环里指针已经指向了结构体的外部。 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的长度(字节数量). 怎么也不会指到外面吧. slzm40 发表于 2014-5-11 12:05
1.那个{}不对是我把上面一些程序去掉了.所以出现错误.实际我编译是对的,我程序里面是完整程序.
2. ...
怎么不会, sizeof(TM) 得到的是结构占用的字节数. slzm40 发表于 2014-5-11 12:05
1.那个{}不对是我把上面一些程序去掉了.所以出现错误.实际我编译是对的,我程序里面是完整程序.
2. ...
是不会指到循环体外面,但会指到结构体外面。 hithms 发表于 2014-5-11 12:16
是不会指到循环体外面,但会指到结构体外面。
最后一步的确地址会大于结构体地址,但不会执行循环程序,指向结构体外有什么影响,只是在判断,不会执行循环程序。 以前一直用数组实现这个,这次用结构体,果然遇到
很多问题啊。 slzm40 发表于 2014-5-11 12:36
最后一步的确地址会大于结构体地址,但不会执行循环程序,指向结构体外有什么影响,只是在判断,不会执行 ...
LZ,缓冲区溢出是一个非常常见的错误,不仅仅出现在你这里,也不仅仅出现在C/C++语言中,而且出问题了还特别难找。
C语言的指针是一把双刃剑,磨刀恨不利,刀利伤人指啊。
就以你这个代码的第二段为例,你很显然希望for循环执行6次,可是你却执行了sizeof(TM)=12次,这样,TM里面的内容是正确改变了,但是TM后续12个字节的内容也被你误伤了,因此说缓冲区溢出。
正确的写法应该是这样的:p<(uint*)&TM+sizeof(TM) / sizeof(uint);,或这样p<(unsigned int *)((unsigned char*)&TM+sizeof(TM));,虽然与你的代码差别不大,但是效果确实完全不一样的。 本帖最后由 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)); 这段完全是地址比较,不是数量比较. 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)啊哥们。自增的你弄明白了,加号的你就犯糊涂了。 takashiki 发表于 2014-5-11 16:16
你既然知道第二段代码的p++是+2,那么你觉得(unsigned int *)((unsigned int*)&TM+sizeof(TM));加的是多 ...
..你这一点,让我明白了.. 第一次在结构体用这样算. 学习了许多啊. 仔细一看汇编.果然是我错了,还是大错特错.果然是2*sizeof(TM).
页:
[1]