打印
[程序源码]

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

[复制链接]
1662|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
oufuqiang|  楼主 | 2023-11-2 15:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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++)               
        {;}                                        //空函数
}
void  main( )                //主函数
{
        uchar display[9]={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[a];        //流水灯显示数据送到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);                        //延时
        }
}




使用特权

评论回复
评论
xch 2023-11-2 20:28 回复TA
@oufuqiang :你的理放之四海而皆准,你可继续按理。 
oufuqiang 2023-11-2 19:53 回复TA
@xch :别激动,这种程序一看就知道是给学生学习中断逻辑的上课内容了。 按理来说不管怎么改参数类型都应该报警告,现在我就是不能解释为什么char和int不报 
xch 2023-11-2 18:57 回复TA
主循环和几个不同中断服务函数调用了同一个函数,函数中对变量操作的指令不是原子指令。所以警告了。 你另外写几个专用的函数给各家调用即可解决。 不过这种在中断函数中嵌入软件延时的方法确实很垃圾 

相关帖子

沙发
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字节
不报警告

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

使用特权

评论回复
5
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.

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

使用特权

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

使用特权

评论回复
7
oufuqiang|  楼主 | 2023-11-12 17:52 | 只看该作者
datouyuan 发表于 2023-11-10 17:19
地板已经解答得很清楚了。
这种报警只存在于51mcu中。其它mcu的临时变量是在堆栈上,不会有这警告。
函数用 ...

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

使用特权

评论回复
8
datouyuan| | 2023-11-13 09:04 | 只看该作者
Keil C51 的局部变量并不是在堆栈中, C51 为了提高代码的效率, 根据 51 处理器的特性. 编译器对函数局部变量的安排进行了处理.局部变量如果不能分配到 寄存器里, 就放在 RAM 中了.编译器通过覆盖分析, 可以共享局部变量的地址空间.。

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

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

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

使用特权

评论回复
9
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,所以报警。

使用特权

评论回复
10
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     

使用特权

评论回复
11
zwsam| | 2023-12-14 09:36 | 只看该作者

使用特权

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

本版积分规则

106

主题

1408

帖子

20

粉丝