oufuqiang 发表于 2023-11-2 15:15

为何改变函数形参会导致报WARNING L15: MULTIPLE CALL TO SEGMENT

本帖最后由 oufuqiang 于 2023-11-2 15:18 编辑

*** WARNING L15: MULTIPLE CALL TO SEGMENT
void Delay(long i)                //延时函数Delay( )
{      
      unsigned int j;
      for(;i > 0;i--)               
      for(j=0;j<125;j++)               
      {;}                                        //空函数
}
神奇之处在于参数类型填char,int,都不报这个警告,改long,或void,就会报这个警告。
按理说,不管参数是什么类型,都会报这个警告才对。
无法理解,望各位解答,谢谢。


#include <reg51.h>
#define uchar unsigned char
void Delay(long i)                //延时函数Delay( )
{      
      unsigned int j;
      for(;i > 0;i--)               
      for(j=0;j<125;j++)               
      {;}                                        //空函数
}
voidmain( )                //主函数
{
      uchar display={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};      
    uchar a;
for(;;)               
{
      EA=1;                        //总中断允许
      EX0=1;                        //允许外部中断0中断
      EX1=1;                        //允许外部中断1中断
      IT0=1;                        //选择外部中断0为跳沿触发方式
      IT1=1;                        //选择外部中断1为跳沿触发方式
      PX0=0;                        //外部中断0为低优先级
      PX1=1;                        //外部中断1为高优先级

      for(a=0;a<9;a++)               
      {                                                
                Delay(500);      //延时
                P1=display;      //流水灯显示数据送到P1口驱动LED显示
      }

}
}
void int0_isr(void)interrupt 0    //外中断0中断函数
{      
      for(;;)
      {
                P1=0x0f;                //低4位LED灭,高4位LED亮
                Delay(400);                //延时
                P1=0xf0;                //高4位LED灭,低4位LED亮
                Delay(400);                //延时
      }                                                         
}
void int1_isr (void)interrupt 2    //外中断1中断函数
{
      uchar m;
      for(m=0;m<5;m++)                        //8位LED全亮全灭5次
      {
                P1=0;                              //8位LED全亮
               Delay(500);                        //延时
               P1=0xff;                        //8位LED全灭
               Delay(500);                        //延时
      }
}




ayb_ice 发表于 2023-11-2 15:36

改了以后函数不重入(变量不能完全被寄存器替代),中断和主循环都调用,会警告,

oufuqiang 发表于 2023-11-2 16:16

ayb_ice 发表于 2023-11-2 15:36
改了以后函数不重入(变量不能完全被寄存器替代),中断和主循环都调用,会警告, ...

char 1字节
int 2字节
不报警告
long 4字节
void 空
报警告
也说不通呢

ayb_ice 发表于 2023-11-3 08:42

oufuqiang 发表于 2023-11-2 16:16
char 1字节
int 2字节
不报警告


变量少,字长短,变量可以分配给寄存器,所以是重入的,另外你不在中断里调用延时函数,不会报警

oufuqiang 发表于 2023-11-9 18:08

Warning L15
Summary *** Warning L15

Multiple Call to Segment
Segment: segment-name
Caller 1: segment-name
Caller 2: segment-name

Description The specified segment is called from two levels, CALLER1, and CALLER2; e.g., main and interrupt program. This has the same effect as a recursive call and may thus lead to the overwriting of parameters or data.

自身帮助里面并没有提及参数的问题
所以参数类型能改变结果也是很神奇

datouyuan 发表于 2023-11-10 17:19

地板已经解答得很清楚了。
这种报警只存在于51mcu中。其它mcu的临时变量是在堆栈上,不会有这警告。
函数用的临时变量全部是寄存器变量,不会报警。只要有一个不是寄存器变量就会报警。
形参类型的变化,函数内部有复杂计算都可能造成有部分临时变量不是寄存器变量,所以报警。

oufuqiang 发表于 2023-11-12 17:52

datouyuan 发表于 2023-11-10 17:19
地板已经解答得很清楚了。
这种报警只存在于51mcu中。其它mcu的临时变量是在堆栈上,不会有这警告。
函数用 ...

是有关联没错,但是我不能理解为何不同变量类型,有些报有些不报。
变量类型就是1-4个字节,指针也差不多。一个字节就R7,字节多了就用到R6,R5,R4一直排下去。
其实关键是重入的问题,只要有重入,就应该都报这个警告。
但是现在char和int不报,空和long都报。

datouyuan 发表于 2023-11-13 09:04

Keil C51 的局部变量并不是在堆栈中, C51 为了提高代码的效率, 根据 51 处理器的特性. 编译器对函数局部变量的安排进行了处理.局部变量如果不能分配到 寄存器里, 就放在 RAM 中了.编译器通过覆盖分析, 可以共享局部变量的地址空间.。

函数的局部变量全部在寄存器中,编译器可以通过堆栈保存临时临时变量,重入不会报警(这和其它mcu一样)。

注意这报警只有keilC51并且满足特定条件才有,是小概率事件。换IAR编译器或换其它非51系列mcu,不会有这报警。

“其实关键是重入的问题,只要有重入,就应该都报这个警告。”,你观念是错误的。

datouyuan 发表于 2023-11-13 16:31

oufuqiang 发表于 2023-11-12 17:52
是有关联没错,但是我不能理解为何不同变量类型,有些报有些不报。
变量类型就是1-4个字节,指针也差不多 ...

看看keil51的汇编代码就知道了。
Delay(char)函数使用了R7R5R4,keil进出中断会自动把这3个寄存器通过堆栈保护还原。
Delay(int)函数使用了R7R6R5R4,keil进出中断会自动把这4个寄存器通过堆栈保护还原。

Delay(long)函数使用了R0~7外,还使用了4字节ram。keil进出中断只保护还原了R0~7,所以报警。

oufuqiang 发表于 2023-11-15 10:14

    37:               Delay(114400);                //延时
C:0x0222    7FE0   MOV      R7,#ACC(0xE0)
C:0x0224    7EBE   MOV      R6,#0xBE
C:0x0226    7D01   MOV      R5,#0x01
C:0x0228    7C00   MOV      R4,#0x00
C:0x022A    120180   LCALL    Delay(C:0180)

   3: void Delay(long i)                //延时函数Delay( )
C:0x0180    8F1E   MOV      0x1E,R7
C:0x0182    8E1D   MOV      0x1D,R6
C:0x0184    8D1C   MOV      0x1C,R5
C:0x0186    8C1B   MOV      0x1B,R4
   4: {         
   5:         unsigned int j;
   6:         for(;i > 0;i--)               
C:0x0188    E4       CLR      A
C:0x0189    FF       MOV      R7,A
C:0x018A    FE       MOV      R6,A
C:0x018B    FD       MOV      R5,A
C:0x018C    FC       MOV      R4,A
C:0x018D    AB1E   MOV      R3,0x1E
C:0x018F    AA1D   MOV      R2,0x1D
C:0x0191    A91C   MOV      R1,0x1C
C:0x0193    A81B   MOV      R0,0x1B
C:0x0195    D3       SETB   C
C:0x0196    12010C   LCALL    C?SLCMP(C:010C)
C:0x0199    4028   JC       C:01C3
   7:         for(j=0;j<125;j++)               
C:0x019B    E4       CLR      A
C:0x019C    FF       MOV      R7,A
C:0x019D    FE       MOV      R6,A
   8:         {;}                                        //空函数
C:0x019E    0F       INC      R7
C:0x019F    BF0001   CJNE   R7,#0x00,C:01A3
C:0x01A2    0E       INC      R6
C:0x01A3    EF       MOV      A,R7
C:0x01A4    647D   XRL      A,#0x7D
C:0x01A6    4E       ORL      A,R6
C:0x01A7    70F5   JNZ      C:019E
C:0x01A9    74FF   MOV      A,#0xFF
C:0x01AB    251E   ADD      A,0x1E
C:0x01AD    F51E   MOV      0x1E,A
C:0x01AF    E51D   MOV      A,0x1D
C:0x01B1    34FF   ADDC   A,#0xFF
C:0x01B3    F51D   MOV      0x1D,A
C:0x01B5    E51C   MOV      A,0x1C
C:0x01B7    34FF   ADDC   A,#0xFF
C:0x01B9    F51C   MOV      0x1C,A
C:0x01BB    E51B   MOV      A,0x1B
C:0x01BD    34FF   ADDC   A,#0xFF
C:0x01BF    F51B   MOV      0x1B,A
C:0x01C1    80C5   SJMP   C:0188
   9: }
C:0x01C3    22       RET      

    42: void int1_isr (void)interrupt 2    //外中断1中断函数
    43: {
    44:         uchar m;
C:0x0122    C0E0   PUSH   ACC(0xE0)
C:0x0124    C0F0   PUSH   B(0xF0)
C:0x0126    C083   PUSH   DPH(0x83)
C:0x0128    C082   PUSH   DPL(0x82)
C:0x012A    C0D0   PUSH   PSW(0xD0)
C:0x012C    75D000   MOV      PSW(0xD0),#0x00
C:0x012F    C000   PUSH   0x00
C:0x0131    C001   PUSH   0x01
C:0x0133    C002   PUSH   0x02
C:0x0135    C003   PUSH   0x03
C:0x0137    C004   PUSH   0x04
C:0x0139    C005   PUSH   0x05
C:0x013B    C006   PUSH   0x06
C:0x013D    C007   PUSH   0x07
    45:         for(m=0;m<5;m++)                        //8位LED全亮全灭5次
C:0x013F    750C00   MOV      0x0C,#0x00
C:0x0142    C3       CLR      C
C:0x0143    E50C   MOV      A,0x0C
C:0x0145    9405   SUBB   A,#0x05
C:0x0147    7480   MOV      A,#P0(0x80)
C:0x0149    9480   SUBB   A,#P0(0x80)
C:0x014B    5010   JNC      C:015D
    46:         {
    47:               P1=0;                              //8位LED全亮
C:0x014D    759000   MOV      P1(0x90),#0x00
    48:                  Delay(500);                        //延时
C:0x0150    120178   LCALL    L?0023(C:0178)
    49:                  P1=0xff;                        //8位LED全灭
C:0x0153    7590FF   MOV      P1(0x90),#0xFF
    50:                  Delay(500);                        //延时
C:0x0156    120178   LCALL    L?0023(C:0178)
    51:         }
C:0x0159    050C   INC      0x0C
C:0x015B    80E5   SJMP   C:0142
    52: }
C:0x015D    D007   POP      0x07
C:0x015F    D006   POP      0x06
C:0x0161    D005   POP      0x05
C:0x0163    D004   POP      0x04
C:0x0165    D003   POP      0x03
C:0x0167    D002   POP      0x02
C:0x0169    D001   POP      0x01
C:0x016B    D000   POP      0x00
C:0x016D    D0D0   POP      PSW(0xD0)
C:0x016F    D082   POP      DPL(0x82)
C:0x0171    D083   POP      DPH(0x83)
C:0x0173    D0F0   POP      B(0xF0)
C:0x0175    D0E0   POP      ACC(0xE0)
C:0x0177    32       RETI   

zwsam 发表于 2023-12-14 09:36

页: [1]
查看完整版本: 为何改变函数形参会导致报WARNING L15: MULTIPLE CALL TO SEGMENT