打印

请教高手一个关于KEIL C的问题~

[复制链接]
4002|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dudongdao|  楼主 | 2007-10-13 20:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
   在KEIL C中,定义 一个指针变量如"unsigned char p;"这个变量为什么即可以指向数据区,又可以指向程序区呢?如果我编写一个函数如
    (void)IncUartRxP(unsigned char* p)
    {
         while(*p != 0)
         {
             sbuf = *p;
             p++;
             DlyMs(20);
          }
   }
   可以这样使用:
     unsigned char code initok[] = "InIt Ok";   //程序区
     unsigned char data test[] = ['T','e','s','t',0];//数据区
    IncUartRxP(initok);
    IncUartRxP(test);
    编译器没有给出警告或者错误信息,根据结果来看,是可以正常执行的,
    但是这样讲不通啊,函数IncUartRxP是固定的,当他执行如sbuf = *p; 
    的时候,到底是从哪里取数据呢, DATA 区,还是CODE区呢?
请指点迷津啊

相关帖子

沙发
zusen| | 2007-10-13 20:59 | 只看该作者

你的数组在那,就在那取数嘛

使用特权

评论回复
板凳
hotpower| | 2007-10-13 21:02 | 只看该作者

对于51系统是难题~~~

因为movc和mov,movx是有区别的~~~

使用特权

评论回复
地板
zusen| | 2007-10-13 21:07 | 只看该作者

定义在那里,51是有专用的关健字的

code
data
idata
xdata
等等等

使用特权

评论回复
5
dudongdao|  楼主 | 2007-10-13 21:09 | 只看该作者

那如何实现呢,函数是固定的

    你定义的那个子函数是固定的,他不能变了,那它到底是从哪里取呢?我用AVR,这种情况要定义两个,如
   (void)IncUartRxP(unsigned char* p);//这个从数据区取数的,所以你用
 编译器编译的时候他会知道从数据区取,就用从数据区取数的机器码来完成.

   (void)IncUartRxP( unsigned char* flash p);//这个从c程序区取数的,所以你用编译器编译的时候他会知道从程序区取,就用从程序区取数的机器码来完成.

如果是51的话,它的子程序执行sbuf = *p;这句的时候,到底是解释成MOV(从数据区取)呢,还是解释成MOVC(从程序区取)呢?按道理是不能改变的,因为你子程序是固定的,如果是两者兼顾的话,也可以,那是不是太麻烦了呢?  真正的情况是如何的呢,继续请高手指点啊,我一直想不通这个问题.
  

使用特权

评论回复
6
dudongdao|  楼主 | 2007-10-13 21:11 | 只看该作者

可以不定义

4楼: 定义在那里,51是有专用的关健字的 

code
data
datai
datax
等等等 
 

可以不定义,我说的是不定义的那种情况

使用特权

评论回复
7
xwj| | 2007-10-13 21:14 | 只看该作者

对于知道的,就直接用正确的指令,对于不知道的,就用3字

有一个字节是存储器类型


怎么老是有不看帮助就瞎问的人呢?

自己去看看Keil的帮助吧,有详细说明的哦

使用特权

评论回复
8
zusen| | 2007-10-13 21:18 | 只看该作者

我说是是数组的定义

指针就不虽要了
你数组定义在那里,传递组指针的只是一个地址
他如根据地址 而去做用 MOV MOVC MOVX

使用特权

评论回复
9
computer00| | 2007-10-13 21:22 | 只看该作者

对,keil的帮助里面有讲的,有个指针类型,

编译的时候自动帮你多传递一个参数进去. 这个你也可以通过查看汇编代码来印证.

使用特权

评论回复
10
dudongdao|  楼主 | 2007-10-13 21:24 | 只看该作者

我看了,没看到具体的

7楼: 对于知道的,就直接用正确的指令,对于不知道的,就用3字节指针 

有一个字节是存储器类型


怎么老是有不看帮助就瞎问的人呢?

自己去看看Keil的帮助吧,有详细说明的哦 
 
这个我以前也看过,从汇编代码上看是这样的,如果你指向的是程序区,比如
     unsigned char code initok[] = "InIt Ok";   //程序区
     unsigned char data test[] = ['T','e','s','t',0];//数据区
     P=initok;那么P的最高字节是0XFF,另外两个字节是真正地址
     P=test;那么P的最高字节是0X00,另外两个字节是真正地址
    
    就算是这样,那子函数是怎么做的呢,是MOV和MOVC,MOVX等都生成,然后根据最高位判断调用哪个吗,关于这个我门看到具体的,请指点啊,你刚才说的不是很
明白,好象对问题的实质没太大帮助,请具体回答,谢谢了

使用特权

评论回复
11
xwj| | 2007-10-13 21:26 | 只看该作者

你自己都基本猜到了,就不会去验证一下吗?

使用特权

评论回复
12
dudongdao|  楼主 | 2007-10-13 21:28 | 只看该作者

函数

我看他的LST文件的时候 找不到那段具体的汇编代码,他是把指针付值之后就调用那个函数了,但是我怎么也找不到那个函数,怪了!!!

使用特权

评论回复
13
dld2| | 2007-10-13 21:28 | 只看该作者

想了解编译器,反汇编阿

使用特权

评论回复
14
computer00| | 2007-10-13 21:29 | 只看该作者

是的,就是根据那个参数决定的,

都生成了代码,根据不同的参数,选择是取什么地址. 这个你可以单步调试追踪下去就能得到结果了。

使用特权

评论回复
15
dudongdao|  楼主 | 2007-10-13 21:30 | 只看该作者

可以说清楚些吗?

我以前也看过KEILC帮助,是说用三个字节存储解决问题,当时只是记住了,具体是怎么实现的不清楚,我是新手啊,请老同志们帮忙

使用特权

评论回复
16
hotpower| | 2007-10-14 09:10 | 只看该作者

这个只有IAR FOR MCS51 C++可以解决,即函数重载.

使用特权

评论回复
17
computer00| | 2007-10-14 09:44 | 只看该作者

呵呵,hotpower大叔,keil C51的编译器自己就有重载呢~~~

看看这个测试代码:

///////////////////main函数////////////////////
     5: void main(void) 
     6: { 
     7:  code unsigned char x=3; //x为code区变量
     8:  test(&x);    //调用test函数
C:0x0028    7BFF     MOV      R3,#0xFF  ;R3为指针类型,这个是由keil编译时根据参数的类型自己加上的
C:0x002A    7A00     MOV      R2,#0x00  ;这个是x这个变量的地址的高8位
C:0x002C    7938     MOV      R1,#0x38  ;这个是x这个变量的地址的低8位
C:0x002E    120032   LCALL    test(C:0032) ;调用函数test
     9: } 
    10:  
C:0x0031    22       RET      //main函数返回



//////////////test函数///////////////
    11: void test(unsigned char *p) 
    12: { 
    13:  P0=*p;  //这个函数只有一句: P0 = *p;
C:0x0032    120003   LCALL    C?CLDPTR(C:0003)  ;编译器先调用库函数C?CLDPTR
C:0x0035    F580     MOV      P0(0x80),A  ;C?CLDPTR函数返回的结果就在A中,再将A赋给P0,实际上,C?CLDPTR函数就根据指针类型选择了不同的类型
    14: } 
C:0x0037    22       RET      R3,#0xFE,C:0015  ;test函数返回

/////////C?CLDPTR函数//////////
                 C?CLDPTR:
C:0x0003    BB0106   CJNE     R3,#0x01,C:000C ;根据指针类型(R3)跳转
                                              ;如果R3的值为1,则表示xdata,将指针放放入DPTR
C:0x0006    8982     MOV      DPL(0x82),R1
C:0x0008    8A83     MOV      DPH(0x83),R2
;使用movx指令将DPTR指向的内容放入A并返回
C:0x000A    E0       MOVX     A,@DPTR
C:0x000B    22       RET
     
C:0x000C    5002     JNC      C:0010 ;如果R3的值为0,则表示内部RAM的, 
C:0x000E    E7       MOV      A,@R1  ;根据指针低位用间接寻址将结果放入A
C:0x000F    22       RET      ;返回

C:0x0010    BBFE02   CJNE     R3,#0xFE,C:0015  ;如果R3的值为0xFE,则表示pdata
C:0x0013    E3       MOVX     A,@R1  ;使用R1间接访问pdata
C:0x0014    22       RET      ;返回

;如果都不是以上情况,则说明是code的,应该使用movc指令访问
C:0x0015    8982     MOV      DPL(0x82),R1
C:0x0017    8A83     MOV      DPH(0x83),R2
C:0x0019    E4       CLR      A
C:0x001A    93       MOVC     A,@A+DPTR
C:0x001B    22       RET      


最后那个clr A似乎有点多余,直接 MOVC A,@DPTR 不就得了,呵呵.这个编译器生成的,只能这样了。

使用特权

评论回复
18
沈老| | 2007-10-14 09:48 | 只看该作者

注意库函数"?C?CLDPTR"!

#include <reg51.h>
#include <ABSACC.h>


void IncUartRxP(unsigned char* p)
{
     SBUF = *p;
}
   
code unsigned char x[]="code";
data unsigned char y[]="data";
idata unsigned char z[]="idata";
void main()
{
    IncUartRxP(x);
    IncUartRxP(y);
    IncUartRxP(z);
}
#if 0
             ; FUNCTION _IncUartRxP (BEGIN)
                                           ; SOURCE LINE # 5
;---- Variable 'p' assigned to Register 'R1/R2/R3' ----
                                           ; SOURCE LINE # 6
                                           ; SOURCE LINE # 7
0000 120000      E     LCALL   ?C?CLDPTR
0003 F599              MOV     SBUF,A
                                           ; SOURCE LINE # 8
0005 22                RET     
             ; FUNCTION _IncUartRxP (END)

             ; FUNCTION main (BEGIN)
                                           ; SOURCE LINE # 13
                                           ; SOURCE LINE # 14
                                           ; SOURCE LINE # 15
0000 7BFF              MOV     R3,#0FFH       ;code !
0002 7A00        R     MOV     R2,#HIGH x
0004 7900        R     MOV     R1,#LOW x
0006 120000      R     LCALL   _IncUartRxP
                                           ; SOURCE LINE # 16
0009 7B00              MOV     R3,#00H       ;data !
000B 7A00        R     MOV     R2,#HIGH y
000D 7900        R     MOV     R1,#LOW y
000F 120000      R     LCALL   _IncUartRxP
                                           ; SOURCE LINE # 17
0012 7A00        R     MOV     R2,#HIGH z  ;idata !
0014 7900        R     MOV     R1,#LOW z
0016 020000      R     LJMP    _IncUartRxP
             ; FUNCTION main (END)

#endif

使用特权

评论回复
19
yanfengzhu| | 2007-10-14 09:57 | 只看该作者

软件调试跟踪一下不就明白了。

使用特权

评论回复
20
dudongdao|  楼主 | 2007-10-14 14:02 | 只看该作者

多谢 !!!

   这下明白了,但是在我的LST文件里怎么找不到?C?CLDPTR 这个函数的具体定义呢.看来还是指定特定区域的比较好,可以节省内存,又可以少代码~~ 
   多谢~~~  学习了~~~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

413

帖子

1

粉丝