slzm40 发表于 2014-5-11 09:54:11

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

本帖最后由 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

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

slzm40 发表于 2014-5-11 10:00:09

声明下.我的MCU是8位的.

qq302011 发表于 2014-5-11 10:09:22

我觉得第一个有问题

slzm40 发表于 2014-5-11 10:18:41

qq302011 发表于 2014-5-11 10:09
我觉得第一个有问题

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

Vampireyifeng 发表于 2014-5-11 10:25:58

什么叫“原源码人家用了很久了..也不会有什么错”

takashiki 发表于 2014-5-11 10:46:07

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

hithms 发表于 2014-5-11 10:56:06

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

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

macaroni 发表于 2014-5-11 11:31:04

个人感觉结构体定义成这样可能是因为内存对齐问题

hithms 发表于 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。所以第二个式子循环里指针已经指向了结构体的外部。

slzm40 发表于 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的长度(字节数量). 怎么也不会指到外面吧.

yyts 发表于 2014-5-11 12:10:07

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

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

hithms 发表于 2014-5-11 12:16:14

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

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

slzm40 发表于 2014-5-11 12:36:38

hithms 发表于 2014-5-11 12:16
是不会指到循环体外面,但会指到结构体外面。

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

takashiki 发表于 2014-5-11 12:47:53

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: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)); 这段完全是地址比较,不是数量比较.

takashiki 发表于 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)啊哥们。自增的你弄明白了,加号的你就犯糊涂了。

slzm40 发表于 2014-5-11 16:36:54

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

..你这一点,让我明白了.. 第一次在结构体用这样算. 学习了许多啊. 仔细一看汇编.果然是我错了,还是大错特错.果然是2*sizeof(TM).
页: [1]
查看完整版本: 寻问指针地址运算与指针所指向数据类型疑问