有符号除数的 % 运算符在 C 中需要更多的程序内存
% operator on signed divisor needs more program memory in C
案例 1:
static uint8_t i;
i % 3; // 3 is a signed number
案例 2:
static uint8_t i;
i % 3u; // 3 is a unsigned number
使用Microchip XC8编译器,我发现情况1需要更多的指令(使用的程序内存增加很少)。
为什么?
注:8 位 CPU。 XC8编译器符合C89标准
程序集:
225: if(KEYbits.I2C == ON && h%5u == 0){
02F2 1ED2 BTFSS KEYbits, 0x5
02F3 2AF5 GOTO 0x2F5
02F4 2AF6 GOTO 0x2F6
02F5 2C75 GOTO 0x475
02F6 3005 MOVLW 0x5
02F7 00F0 MOVWF __pcstackCOMMON
02F8 3000 MOVLW 0x0
02F9 00F1 MOVWF hold
02FA 0850 MOVF h, W
02FB 00DE MOVWF 0x5E
02FC 01DF CLRF 0x5F
02FD 085E MOVF 0x5E, W
02FE 00F2 MOVWF product
02FF 085F MOVF 0x5F, W
0300 00F3 MOVWF multiplier
0301 318A MOVLP 0xA //here
0302 22B4 CALL 0x2B4 //here
0303 3180 MOVLP 0x0
0304 0870 MOVF __pcstackCOMMON, W
0305 0471 IORWF hold, W
0306 1D03 BTFSS STATUS, 0x2
0307 2B09 GOTO 0x309
0308 2B0A GOTO 0x30A
0309 2C75 GOTO 0x475
226: h = 0;
02B4 0834 MOVF TMR4_counter, W
02B5 07DE ADDWF 0x5E, F
02B6 0835 MOVF 0x35, W
02B7 3DDF ADDWFC 0x5F, F
02B8 0836 MOVF 0x36, W
02B9 3DE0 ADDWFC 0x60, F
02BA 0837 MOVF 0x37, W
02BB 3DE1 ADDWFC 0x61, F
02BC 0861 MOVF 0x61, W
02BD 00B7 MOVWF 0x37
02BE 0860 MOVF 0x60, W
02BF 00B6 MOVWF 0x36
02C0 085F MOVF 0x5F, W
02C1 00B5 MOVWF 0x35
02C2 085E MOVF 0x5E, W
02C3 00B4 MOVWF TMR4_counter
225: if(KEYbits.I2C == ON && h%5 == 0){
02F2 1ED2 BTFSS KEYbits, 0x5
02F3 2AF5 GOTO 0x2F5
02F4 2AF6 GOTO 0x2F6
02F5 2C75 GOTO 0x475
02F6 3005 MOVLW 0x5
02F7 00F0 MOVWF __pcstackCOMMON
02F8 3000 MOVLW 0x0
02F9 00F1 MOVWF hold
02FA 0850 MOVF h, W
02FB 00DE MOVWF 0x5E
02FC 01DF CLRF 0x5F
02FD 085E MOVF 0x5E, W
02FE 00F2 MOVWF product
02FF 085F MOVF 0x5F, W
0300 00F3 MOVWF multiplier
0301 3186 MOVLP 0x6 //here
0302 2663 CALL 0x663 //here
0303 3180 MOVLP 0x0
0304 0870 MOVF __pcstackCOMMON, W
0305 0471 IORWF hold, W
0306 1D03 BTFSS STATUS, 0x2
0307 2B09 GOTO 0x309
0308 2B0A GOTO 0x30A
0309 2C75 GOTO 0x475
226: h = 0;
0663 01F6 CLRF sign
14: if(dividend < 0) {
0664 1FF3 BTFSS multiplier, 0x7
0665 2E67 GOTO 0x667
0666 2E68 GOTO 0x668
0667 2E70 GOTO 0x670
15: dividend = -dividend;
0668 09F2 COMF product, F
0669 09F3 COMF multiplier, F
066A 0AF2 INCF product, F
066B 1903 BTFSC STATUS, 0x2
066C 0AF3 INCF multiplier, F
16: sign = 1;
066D 01F6 CLRF sign
066E 0AF6 INCF sign, F
066F 2E70 GOTO 0x670
对%
的操作数执行usual arithmetic conversions。我猜 i
是有符号类型; i % 3
的结果可能与 i % 3u
的结果不同。
例如,-1 % 3u
通常是 0
,因为在转换为 unsigned int
之后,-1
通常会变成比 2 的偶数次方小一,例如65535
或 4294967295
,始终是 3 的倍数。
但是 -1 % 3
在 C89 中要么是 -1
要么是 2
(这是实现定义的)。
按理说,编译器可能必须针对这两种不同的情况发出不同的汇编指令。
对问题的编辑不会改变这一点; uint8_t
被提升为有符号 int
,优化器可能没有意识到它可以在这两种情况下使用 "better" 程序集。
案例 1:
static uint8_t i;
i % 3; // 3 is a signed number
案例 2:
static uint8_t i;
i % 3u; // 3 is a unsigned number
使用Microchip XC8编译器,我发现情况1需要更多的指令(使用的程序内存增加很少)。 为什么?
注:8 位 CPU。 XC8编译器符合C89标准
程序集:
225: if(KEYbits.I2C == ON && h%5u == 0){
02F2 1ED2 BTFSS KEYbits, 0x5
02F3 2AF5 GOTO 0x2F5
02F4 2AF6 GOTO 0x2F6
02F5 2C75 GOTO 0x475
02F6 3005 MOVLW 0x5
02F7 00F0 MOVWF __pcstackCOMMON
02F8 3000 MOVLW 0x0
02F9 00F1 MOVWF hold
02FA 0850 MOVF h, W
02FB 00DE MOVWF 0x5E
02FC 01DF CLRF 0x5F
02FD 085E MOVF 0x5E, W
02FE 00F2 MOVWF product
02FF 085F MOVF 0x5F, W
0300 00F3 MOVWF multiplier
0301 318A MOVLP 0xA //here
0302 22B4 CALL 0x2B4 //here
0303 3180 MOVLP 0x0
0304 0870 MOVF __pcstackCOMMON, W
0305 0471 IORWF hold, W
0306 1D03 BTFSS STATUS, 0x2
0307 2B09 GOTO 0x309
0308 2B0A GOTO 0x30A
0309 2C75 GOTO 0x475
226: h = 0;
02B4 0834 MOVF TMR4_counter, W
02B5 07DE ADDWF 0x5E, F
02B6 0835 MOVF 0x35, W
02B7 3DDF ADDWFC 0x5F, F
02B8 0836 MOVF 0x36, W
02B9 3DE0 ADDWFC 0x60, F
02BA 0837 MOVF 0x37, W
02BB 3DE1 ADDWFC 0x61, F
02BC 0861 MOVF 0x61, W
02BD 00B7 MOVWF 0x37
02BE 0860 MOVF 0x60, W
02BF 00B6 MOVWF 0x36
02C0 085F MOVF 0x5F, W
02C1 00B5 MOVWF 0x35
02C2 085E MOVF 0x5E, W
02C3 00B4 MOVWF TMR4_counter
225: if(KEYbits.I2C == ON && h%5 == 0){
02F2 1ED2 BTFSS KEYbits, 0x5
02F3 2AF5 GOTO 0x2F5
02F4 2AF6 GOTO 0x2F6
02F5 2C75 GOTO 0x475
02F6 3005 MOVLW 0x5
02F7 00F0 MOVWF __pcstackCOMMON
02F8 3000 MOVLW 0x0
02F9 00F1 MOVWF hold
02FA 0850 MOVF h, W
02FB 00DE MOVWF 0x5E
02FC 01DF CLRF 0x5F
02FD 085E MOVF 0x5E, W
02FE 00F2 MOVWF product
02FF 085F MOVF 0x5F, W
0300 00F3 MOVWF multiplier
0301 3186 MOVLP 0x6 //here
0302 2663 CALL 0x663 //here
0303 3180 MOVLP 0x0
0304 0870 MOVF __pcstackCOMMON, W
0305 0471 IORWF hold, W
0306 1D03 BTFSS STATUS, 0x2
0307 2B09 GOTO 0x309
0308 2B0A GOTO 0x30A
0309 2C75 GOTO 0x475
226: h = 0;
0663 01F6 CLRF sign
14: if(dividend < 0) {
0664 1FF3 BTFSS multiplier, 0x7
0665 2E67 GOTO 0x667
0666 2E68 GOTO 0x668
0667 2E70 GOTO 0x670
15: dividend = -dividend;
0668 09F2 COMF product, F
0669 09F3 COMF multiplier, F
066A 0AF2 INCF product, F
066B 1903 BTFSC STATUS, 0x2
066C 0AF3 INCF multiplier, F
16: sign = 1;
066D 01F6 CLRF sign
066E 0AF6 INCF sign, F
066F 2E70 GOTO 0x670
对%
的操作数执行usual arithmetic conversions。我猜 i
是有符号类型; i % 3
的结果可能与 i % 3u
的结果不同。
例如,-1 % 3u
通常是 0
,因为在转换为 unsigned int
之后,-1
通常会变成比 2 的偶数次方小一,例如65535
或 4294967295
,始终是 3 的倍数。
但是 -1 % 3
在 C89 中要么是 -1
要么是 2
(这是实现定义的)。
按理说,编译器可能必须针对这两种不同的情况发出不同的汇编指令。
对问题的编辑不会改变这一点; uint8_t
被提升为有符号 int
,优化器可能没有意识到它可以在这两种情况下使用 "better" 程序集。