为何改变函数形参会导致报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
改了以后函数不重入(变量不能完全被寄存器替代),中断和主循环都调用,会警告, ...
char 1字节
int 2字节
不报警告
long 4字节
void 空
报警告
也说不通呢 oufuqiang 发表于 2023-11-2 16:16
char 1字节
int 2字节
不报警告
变量少,字长短,变量可以分配给寄存器,所以是重入的,另外你不在中断里调用延时函数,不会报警 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.
自身帮助里面并没有提及参数的问题
所以参数类型能改变结果也是很神奇 地板已经解答得很清楚了。
这种报警只存在于51mcu中。其它mcu的临时变量是在堆栈上,不会有这警告。
函数用的临时变量全部是寄存器变量,不会报警。只要有一个不是寄存器变量就会报警。
形参类型的变化,函数内部有复杂计算都可能造成有部分临时变量不是寄存器变量,所以报警。
datouyuan 发表于 2023-11-10 17:19
地板已经解答得很清楚了。
这种报警只存在于51mcu中。其它mcu的临时变量是在堆栈上,不会有这警告。
函数用 ...
是有关联没错,但是我不能理解为何不同变量类型,有些报有些不报。
变量类型就是1-4个字节,指针也差不多。一个字节就R7,字节多了就用到R6,R5,R4一直排下去。
其实关键是重入的问题,只要有重入,就应该都报这个警告。
但是现在char和int不报,空和long都报。 Keil C51 的局部变量并不是在堆栈中, C51 为了提高代码的效率, 根据 51 处理器的特性. 编译器对函数局部变量的安排进行了处理.局部变量如果不能分配到 寄存器里, 就放在 RAM 中了.编译器通过覆盖分析, 可以共享局部变量的地址空间.。
函数的局部变量全部在寄存器中,编译器可以通过堆栈保存临时临时变量,重入不会报警(这和其它mcu一样)。
注意这报警只有keilC51并且满足特定条件才有,是小概率事件。换IAR编译器或换其它非51系列mcu,不会有这报警。
“其实关键是重入的问题,只要有重入,就应该都报这个警告。”,你观念是错误的。 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,所以报警。
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
页:
[1]