|
瞎搞就是硬道理(何必讲什么大道理)
对testcode的GCC转换为类成员的指针的方法进行了调试及反汇编列表,结果确实不太满意。
虽然运行正常但代码太长,导致我对三种散转的对比报告成为一堆废纸。
使我真的被“梁山好汉”招安入伙,成了第109名“水寇”终于“晚节不保”,心情难以平静。。。
放手一博,瞎搞就是硬道理!!!
先请看类成员的指针的方法的反汇编代码列表:
268: void KeyObj::KeyCommandExec(unsigned char mode)
269: {
+00000078: 930F PUSH R16 Push register on stack
+00000079: 931F PUSH R17 Push register on stack
+0000007A: 93CF PUSH R28 Push register on stack
+0000007B: 93DF PUSH R29 Push register on stack
+0000007C: B7CD IN R28,0x3D In from I/O location
+0000007D: B7DE IN R29,0x3E In from I/O location
+0000007E: 9724 SBIW R28,0x04 Subtract immediate from word
+0000007F: B60F IN R0,0x3F In from I/O location
+00000080: 94F8 CLI Global Interrupt Disable
+00000081: BFDE OUT 0x3E,R29 Out to I/O location
+00000082: BE0F OUT 0x3F,R0 Out to I/O location
+00000083: BFCD OUT 0x3D,R28 Out to I/O location
+00000084: 018C MOVW R16,R24 Copy register pair
277: KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确
+00000085: 01FC MOVW R30,R24 Copy register pair
+00000086: 8141 LDD R20,Z+1 Load indirect with displacement
+00000087: 7047 ANDI R20,0x07 Logical AND with immediate
+00000088: 8341 STD Z+1,R20 Store indirect with displacement
278: if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.
+00000089: 3045 CPI R20,0x05 Compare with immediate
+0000008A: F590 BRCC PC+0x33 Branch if carry cleared
286: memcpy_P(&func, &(KeyObj::KeyCommandTab[mode][KeyCount]), sizeof(PFV));
+0000008B: 2F26 MOV R18,R22 Copy register
+0000008C: 2733 CLR R19 Clear Register
+0000008D: 01C9 MOVW R24,R18 Copy register pair
+0000008E: 0F88 LSL R24 Logical Shift Left
+0000008F: 1F99 ROL R25 Rotate Left Through Carry
+00000090: 0F88 LSL R24 Logical Shift Left
+00000091: 1F99 ROL R25 Rotate Left Through Carry
+00000092: 0F82 ADD R24,R18 Add without carry
+00000093: 1F93 ADC R25,R19 Add with carry
+00000094: 0F84 ADD R24,R20 Add without carry
+00000095: 1D91 ADC R25,R1 Add with carry
+00000096: 0F88 LSL R24 Logical Shift Left
+00000097: 1F99 ROL R25 Rotate Left Through Carry
+00000098: 0F88 LSL R24 Logical Shift Left
+00000099: 1F99 ROL R25 Rotate Left Through Carry
+0000009A: 5C86 SUBI R24,0xC6 Subtract immediate
+0000009B: 4F9F SBCI R25,0xFF Subtract immediate with carry
+0000009C: E044 LDI R20,0x04 Load immediate
+0000009D: E050 LDI R21,0x00 Load immediate
+0000009E: 01BC MOVW R22,R24 Copy register pair
+0000009F: 01CE MOVW R24,R28 Copy register pair
+000000A0: 9601 ADIW R24,0x01 Add immediate to word
+000000A1: D317 RCALL PC+0x0318 Relative call subroutine
287: (this->*func)();//运行KeyX0()~KeyX4()
+000000A2: 81EB LDD R30,Y+3 Load indirect with displacement
---- No Source ------------------------------------------------------------------------------------
+000000A3: 81FC LDD R31,Y+4 Load indirect with displacement
+000000A4: 8129 LDD R18,Y+1 Load indirect with displacement
+000000A5: 813A LDD R19,Y+2 Load indirect with displacement
+000000A6: FFE0 SBRS R30,0 Skip if bit in register set
+000000A7: C00B RJMP PC+0x000C Relative jump
+000000A8: 95F5 ASR R31 Arithmetic shift right
+000000A9: 95E7 ROR R30 Rotate right through carry
+000000AA: 0FE0 ADD R30,R16 Add without carry
+000000AB: 1FF1 ADC R31,R17 Add with carry
+000000AC: 8180 LDD R24,Z+0 Load indirect with displacement
+000000AD: 8191 LDD R25,Z+1 Load indirect with displacement
+000000AE: 0F28 ADD R18,R24 Add without carry
+000000AF: 1F39 ADC R19,R25 Add with carry
+000000B0: 01F9 MOVW R30,R18 Copy register pair
+000000B1: 8120 LDD R18,Z+0 Load indirect with displacement
+000000B2: 8131 LDD R19,Z+1 Load indirect with displacement
+000000B3: 01FE MOVW R30,R28 Copy register pair
+000000B4: 9631 ADIW R30,0x01 Add immediate to word
+000000B5: 8182 LDD R24,Z+2 Load indirect with displacement
+000000B6: 8193 LDD R25,Z+3 Load indirect with displacement
+000000B7: 9595 ASR R25 Arithmetic shift right
+000000B8: 9587 ROR R24 Rotate right through carry
+000000B9: 0F80 ADD R24,R16 Add without carry
+000000BA: 1F91 ADC R25,R17 Add with carry
+000000BB: 01F9 MOVW R30,R18 Copy register pair
+000000BC: 9509 ICALL Indirect call to (Z)
+000000BD: 9624 ADIW R28,0x04 Add immediate to word
+000000BE: B60F IN R0,0x3F In from I/O location
+000000BF: 94F8 CLI Global Interrupt Disable
+000000C0: BFDE OUT 0x3E,R29 Out to I/O location
+000000C1: BE0F OUT 0x3F,R0 Out to I/O location
+000000C2: BFCD OUT 0x3D,R28 Out to I/O location
+000000C3: 91DF POP R29 Pop register from stack
+000000C4: 91CF POP R28 Pop register from stack
+000000C5: 911F POP R17 Pop register from stack
+000000C6: 910F POP R16 Pop register from stack
+000000C7: 9508 RET Subroutine return
在+000000A1处调用以下子程序memcpy_P()执行了4次LPM指令得到跳转地址
+000003B9: 01FB MOVW R30,R22 Copy register pair
+000003BA: 01DC MOVW R26,R24 Copy register pair
+000003BB: C002 RJMP PC+0x0003 Relative jump
+000003BC: 9005 LPM R0,Z+ Load program memory and postincrement
+000003BD: 920D ST X+,R0 Store indirect and postincrement
+000003BE: 5041 SUBI R20,0x01 Subtract immediate
+000003BF: 4050 SBCI R21,0x00 Subtract immediate with carry
+000003C0: F7D8 BRCC PC-0x04 Branch if carry cleared
+000003C1: 9508 RET Subroutine return
可以看出从+0000008B开始到+000003C1结束的代码长度真是吓人呀!!!memcpy_P()真是“厉害”!!!
依此结果必被招安!!!我岂能坐以待毙???
所谓“散转”无非是根据数组的值即函数的地址拿出来用ICALL跳即可,即用“函数指针”跳转。
不管是什么样的“指针”,对于MCU就是两字节的地址!!!在跳转时强制转换成Void(*)()指针不就行了吗???
(KeyObj::*)()那是被“逼良为娼,迫不得已”,不然Key00()等的地址从何而来???请看如何瞎搞???
typedef void (KeyObj::* PFV)(void);//类成员函数指针
typedef void (* PV)(void);//一般函数指针
void KeyObj::KeyCommandExec(unsigned char mode)//类成员函数
{
//
static PFV KeyCommandTab[3][5] PROGMEM = {//键盘放事件处理表
{&KeyObj::Key00, &KeyObj::Key01, &KeyObj::Key02, &KeyObj::Key03, &KeyObj::Key04}, //键释放事件处理
{&KeyObj::Key10, &KeyObj::Key11, &KeyObj::Key12, &KeyObj::Key13, &KeyObj::Key14}, //压键事件处理
{&KeyObj::Key20, &KeyObj::Key21, &KeyObj::Key22, &KeyObj::Key23, &KeyObj::Key24} //长压键事件处理
};
//
KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确
if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.
//
PV func;//声明一般函数指针
func = reinterpret_cast<PV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表
func();//运行KeyX0()~KeyX4()
//
/*
PFV func;//声明类成员函数指针
memcpy_P(&func, &(KeyObj::KeyCommandTab[mode][KeyCount]), sizeof(PFV));//取flash键盘放事件处理表
(this->*func)();//运行KeyX0()~KeyX4()
*/
}
}
注意:用PFV指针时KeyCommandTab只能做为静态成员数组,它不能在成员函数内定义。而用PV指针两者皆可,代码又小也灵活。
再看此一般函数指针的反汇编代码列表:(和总结报告三种散转对比基本一致,不过多了2条指令但不用静态成员)(如果采用一维数组代码将更简捷)
269: void KeyObj::KeyCommandExec(unsigned char mode)
270: {
+00000078: 01FC MOVW R30,R24 Copy register pair
278: KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确
+00000079: 8121 LDD R18,Z+1 Load indirect with displacement
+0000007A: 7027 ANDI R18,0x07 Logical AND with immediate
+0000007B: 8321 STD Z+1,R18 Store indirect with displacement
279: if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.
+0000007C: 3025 CPI R18,0x05 Compare with immediate
+0000007D: F4A8 BRCC PC+0x16 Branch if carry cleared
282: func = reinterpret_cast<PV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表
+0000007E: 2F86 MOV R24,R22 Copy register
+0000007F: 2799 CLR R25 Clear Register
+00000080: 01FC MOVW R30,R24 Copy register pair
+00000081: 0FEE LSL R30 Logical Shift Left
+00000082: 1FFF ROL R31 Rotate Left Through Carry
+00000083: 0FEE LSL R30 Logical Shift Left
+00000084: 1FFF ROL R31 Rotate Left Through Carry
+00000085: 0FE8 ADD R30,R24 Add without carry
+00000086: 1FF9 ADC R31,R25 Add with carry
+00000087: 0FE2 ADD R30,R18 Add without carry
+00000088: 1DF1 ADC R31,R1 Add with carry
+00000089: 0FEE LSL R30 Logical Shift Left
+0000008A: 1FFF ROL R31 Rotate Left Through Carry
+0000008B: 0FEE LSL R30 Logical Shift Left
+0000008C: 1FFF ROL R31 Rotate Left Through Carry
+0000008D: 5CE6 SUBI R30,0xC6 Subtract immediate
+0000008E: 4FFF SBCI R31,0xFF Subtract immediate with carry
+0000008F: 9185 LPM R24,Z+ Load program memory and postincrement
+00000090: 9194 LPM R25,Z Load program memory
283: func();//运行KeyX0()~KeyX4()
+00000091: 01FC MOVW R30,R24 Copy register pair
---- No Source ------------------------------------------------------------------------------------
+00000092: 9509 ICALL Indirect call to (Z)
+00000093: 9508 RET Subroutine return
从以上两个反汇编代码列表中很容易看出后者肯定代码执行效率大大地优于前者。吓搞成功!!!
感谢两位陪我在此“唠叨”,但我们三位可以大声地说“以后再也不怕什么成员数组指针了”。。。
不是像有位网友说的什么“钻研精神”,这是一种“傻劲”,几个“不撞南墙不回头”的“傻帽”。
但“傻人”好象特别有“傻福”,我想做的几乎都得到了“成功”。。。
学习和编程甚至是设计产品等都应该如此,从开始“设计”到最后结果的诞生往往看来都是“幼稚可笑”的,因为结果竟是如此简单。
“坐着的人”往往等结果出来时总是对“站着的人”说---“为什么早点不拿把凳子呢,看你站着累不累???我坐着都看着你累。。。”
那么“坐着的人”为什么不早点站起来帮“站着的人”擦把汗呢???
道理很简单:坐着的人坐习惯了,站着的人累习惯了。坐着的人站起来腰痛,站着的人坐下来腿痛。(相信吗???)
最近在此灌水较多,真有些不好意思了。。。请多包涵。。。
|
|