打印

[讨论]用C语言写代码,如何优化代码尺寸大小

[复制链接]
楼主: 古道热肠
手机看帖
扫描二维码
随时随地手机跟帖
61
itelectron| | 2009-7-8 20:41 | 只看该作者 回帖奖励 |倒序浏览

高内聚 不太明白

个人认为 硬件无关**就用OS

使用特权

评论回复
62
hebu007| | 2009-7-9 14:43 | 只看该作者

关注

学习

使用特权

评论回复
63
古道热肠|  楼主 | 2009-7-9 14:49 | 只看该作者

贴个专用算法给大家看看.这个变换是为了节省代码空间使用

unsigned long SwapINT32(unsigned long dData)
{
    union BigLongValue
    {
        ulong  ulReturnValue;
        uchar  ucByte[4];
    } CurrentBigLongValue;

    uchar *ucData;
    
    ucData = (uchar *)&dData;
    CurrentBigLongValue.ucByte[3] = *ucData++;
    CurrentBigLongValue.ucByte[2] = *ucData++;    
    CurrentBigLongValue.ucByte[1] = *ucData++;
    CurrentBigLongValue.ucByte[0] = *ucData++;

    return CurrentBigLongValue.ulReturnValue;
}

此函数虽然节省空间,但与编译器对整型变量的大小端约定关联,故移植时尤其要注意编译坏境的约定.

使用特权

评论回复
64
xwj| | 2009-7-9 15:11 | 只看该作者

节省代码空间? 怎么节省的?

使用特权

评论回复
65
古道热肠|  楼主 | 2009-7-9 15:16 | 只看该作者

写省代码空间是与58楼发贴内容相对比来说的

58楼: 现在的重点是优化代码,其它的肯定也会考虑的 

比如以下函数,用C51写与卡交换数据时多半要用到,如何优化,希望大家提出自己的想法.
unsigned long SwapINT32(unsigned long dData)
{
               dData = ((dData&0xff)<<24) |((dData&0xff00)<<8) |((dData&0xff000000)>>24) | ((dData&0xff0000)>>8);
     
         return dData;
}
 
 

使用特权

评论回复
66
glf| | 2009-7-9 16:54 | 只看该作者

请教

7楼你好:青椒一下为什么计数器尽量用减法啊

使用特权

评论回复
67
古道热肠|  楼主 | 2009-7-10 10:27 | 只看该作者

回楼上,你这问题得看编译后的汇编代码就明白了

减法运算会生成DJNZ指令,效率高.

使用特权

评论回复
68
inter_zhou| | 2009-7-10 19:11 | 只看该作者

回68楼

unsigned long SwapINT32(unsigned long dData)
{
#if 0
    dData = ((dData&0xff)<<24) |((dData&0xff00)<<8) |
        ((dData&0xff000000)>>24) | ((dData&0xff0000)>>8);

#else
    unsigned long temp = dData;
    unsigned char *P =&temp;

    ((unsigned char *)&dData)[0] = ((unsigned char *)&temp[3];  
    ((unsigned char *)&dData)[1] = ((unsigned char *)&temp[2];  
    ((unsigned char *)&dData)[2] = ((unsigned char *)&temp[1];  
    ((unsigned char *)&dData)[3] = ((unsigned char *)&temp[0];  
#endif
    return dData;
}
这种写法可以节省68字节,应该还有更好的,期待能有更好的出来!

使用特权

评论回复
69
inter_zhou| | 2009-7-10 19:52 | 只看该作者

经测试更优化的

unsigned long SwapINT32(u32 dData)
{
//    dData = ((dData&0xff)<<24) |((dData&0xff00)<<8) |
//        ((dData&0xff000000)>>24) | ((dData&0xff0000)>>8);

    unsigned char    buf, buf1;
    
    buf = ((unsigned char *)&dData)[1];  
    buf1 = ((unsigned char *)&dData)[0];    
    
    ((unsigned char *)&dData)[0] = ((unsigned char *)&dDat[3];  
    ((unsigned char *)&dData)[1] = ((unsigned char *)&dDat[2];  
    ((unsigned char *)&dData)[2] = buf;
    ((unsigned char *)&dData)[3] = buf1;

}
比最原始的写法节省94个字节,编译平台KEIL C51,期待更好的!

使用特权

评论回复
70
古道热肠|  楼主 | 2009-7-11 12:25 | 只看该作者

71楼的写法在"atmel硬盘MP3"中见过,72楼应是楼主的创新写法

俺来试试效果,挑战自我的精神值得表扬呀!

使用特权

评论回复
71
古道热肠|  楼主 | 2009-7-11 12:39 | 只看该作者

楼上intel_zho的代码的确很优化,还有更好的不妨上来一博,仅限

    95: unsigned long SwapINT32(unsigned long dData) 
C:0x076C    8F61     MOV      0x61,R7
C:0x076E    8E60     MOV      0x60,R6
C:0x0770    8D5F     MOV      0x5F,R5
C:0x0772    8C5E     MOV      ?_PRINTF517?BYTE(0x5E),R4
   100:     unsigned char    buf, buf1; 
   101:      
   102:     buf = ((unsigned char *)&dData)[1];   
C:0x0774    AF5F     MOV      R7,0x5F
   103:     buf1 = ((unsigned char *)&dData)[0];     
   104:      
C:0x0776    AE5E     MOV      R6,?_PRINTF517?BYTE(0x5E)
   105:     ((unsigned char *)&dData)[0] = ((unsigned char *)&dData)[3];   
C:0x0778    85615E   MOV      ?_PRINTF517?BYTE(0x5E),0x61
   106:     ((unsigned char *)&dData)[1] = ((unsigned char *)&dData)[2];   
C:0x077B    85605F   MOV      0x5F,0x60
   107:     ((unsigned char *)&dData)[2] = buf; 
C:0x077E    8F60     MOV      0x60,R7
   108:     ((unsigned char *)&dData)[3] = buf1; 
   109:  
C:0x0780    8E61     MOV      0x61,R6
   110: } 
   111: #endif 
   112:  
C:0x0782    22       RET      

使用特权

评论回复
72
ayb_ice| | 2009-7-11 14:37 | 只看该作者

现丑了

包含返回代码部分,用C要想高效还是传递指针最好,可以通过指针直接修改原始数据,节省了大量的数据传递时间,那样应该和汇编效率不相上下.

原代码
unsigned long SwapINT32(unsigned long dData)
{
//    dData = ((dData&0xff)<<24) |((dData&0xff00)<<8) |
//        ((dData&0xff000000)>>24) | ((dData&0xff0000)>>8);

    union{
        U8 b[4];
        U32 x;
    }temp;

    temp.b[3] = ((U8*)&dData)[0];
    temp.b[2] = ((U8*)&dData)[1];
    temp.b[1] = ((U8*)&dData)[2];
    temp.b[0] = ((U8*)&dData)[3];

    return temp.x;
}
编译效果
; #define U8  unsigned char
; #define U16 unsigned int
; #define U32 unsigned long


; unsigned long SwapINT32(unsigned long dData)

    RSEG  ?PR?_SwapINT32?MAIN
_SwapINT32:
    USING    0
            ; SOURCE LINE # 130
    MOV      dData?141+03H,R7
    MOV      dData?141+02H,R6
    MOV      dData?141+01H,R5
    MOV      dData?141,R4
; {
            ; SOURCE LINE # 131
; //    dData = ((dData&0xff)<<24) |((dData&0xff00)<<8) |
; //        ((dData&0xff000000)>>24) | ((dData&0xff0000)>>8);

;     union{
;         U8 b[4];
;         U32 x;
;     }temp;

;     temp.b[3] = ((U8*)&dData)[0];
            ; SOURCE LINE # 140
    MOV      temp?142+03H,dData?141
;     temp.b[2] = ((U8*)&dData)[1];
            ; SOURCE LINE # 141
    MOV      temp?142+02H,dData?141+01H
;     temp.b[1] = ((U8*)&dData)[2];
            ; SOURCE LINE # 142
    MOV      temp?142+01H,dData?141+02H
;     temp.b[0] = ((U8*)&dData)[3];
            ; SOURCE LINE # 143
    MOV      temp?142,dData?141+03H

;     return temp.x;
            ; SOURCE LINE # 145
    MOV      R7,temp?142+03H
    MOV      R6,temp?142+02H
    MOV      R5,temp?142+01H
    MOV      R4,temp?142
; }
            ; SOURCE LINE # 146
?C0020:
    RET      
; END OF _SwapINT32

    END

使用特权

评论回复
73
古道热肠|  楼主 | 2009-7-12 10:46 | 只看该作者

经测试75楼的尺寸比72楼的大,不敌inter_zhou,继续努力,再来一回

ayb_ICE的测试结果如图

使用特权

评论回复
74
古道热肠|  楼主 | 2009-7-12 10:49 | 只看该作者

inter-zhou的代码编译尺寸截图

使用特权

评论回复
75
古道热肠|  楼主 | 2009-7-12 10:51 | 只看该作者

贴上集合了网友优化代码的测试项目包

使用特权

评论回复
76
古道热肠|  楼主 | 2009-7-12 10:56 | 只看该作者

俺的理解是要想最优化,得诱导编译器使用XCH指令完成此函数

函数完成的功能实际上就是将入口处R4.R5,R6,R7的内容变换成R7,R6,R5,R4然后返回上层主调函数

理论上最优化的伪码为
MOV ACC,R4
XCH R7,ACC
MOV ACC,R6
XCH R5,ACC
RET

如何引导Keil编译器使用XCH指令,不得其解.

使用特权

评论回复
77
ayb_ice| | 2009-7-12 11:53 | 只看该作者

TO:古道热肠

74L的没有写返回语句,所有小了4条汇编指令语句,用C不可能写出交换寄存器的语句
理由如下:
  如果对某个局部变量进行强制指针变换,那么这个变量不可能被分配给寄存器,因为寄存器的取决于当前的寄存器组,而这个函数要想高效必须进行指针变换.
  实际是这个函数的功能不复杂,语句也少,要想用C写最好传递一个或两个具体指针参数,然后利用指针进行数据交换,不用返回数据,传递具体指针也比传递U32数据效率要高,局部变量也可以被分配给寄存器,这样效率是很高的.指针方式也比用汇编的参数传递和返回参数方式要高效的多.此处用于传递参数的时间已经超过了数据处理的核心时间了...
  

使用特权

评论回复
78
ayb_ice| | 2009-7-12 12:14 | 只看该作者

这种简单的变换操作还是适合用宏操作

源代码
#define U32 unsigned long
#define U8  unsigned char

#define macro_SwapINT32(src, des)
{
    ((U8*)&src)[0] = ((U8*)&des)[3];
    ((U8*)&src)[1] = ((U8*)&des)[2];
    ((U8*)&src)[2] = ((U8*)&des)[1];
    ((U8*)&src)[3] = ((U8*)&des)[0];
}

void test(void)
{
    U32 x,y;

    macro_SwapINT32(x, y);
}
编译效果
; #define macro_SwapINT32(src, des)
; {
;     ((U8*)&src)[0] = ((U8*)&des)[3];
;     ((U8*)&src)[1] = ((U8*)&des)[2];
;     ((U8*)&src)[2] = ((U8*)&des)[1];
;     ((U8*)&src)[3] = ((U8*)&des)[0];
; }

; void test(void)

    RSEG  ?PR?test?MAIN
test:
    USING    0
            ; SOURCE LINE # 106
; {
            ; SOURCE LINE # 107
;     U32 x,y;
            ; SOURCE LINE # 108

;     macro_SwapINT32(x, y);
            ; SOURCE LINE # 110
    MOV      x?141,y?142+03H
    MOV      x?141+01H,y?142+02H
    MOV      x?141+02H,y?142+01H
    MOV      x?141+03H,y?142
; }
            ; SOURCE LINE # 111
    RET      
; END OF test

    END

使用特权

评论回复
79
古道热肠|  楼主 | 2009-7-12 16:47 | 只看该作者

哈哈,是俺看花眼了.inter_zho的函数的确少了return指令.

abc-ice有81楼提出的宏变换的确是高效而又简洁的风格,值得大家学习.

使用特权

评论回复
80
ayb_ice| | 2009-7-12 17:18 | 只看该作者

我发现KEIL在变量分配在寄存器中的优化

显得不够聪明,明显的字节返回值在R7里是不合理的做法,因为对返回值的判断时还是要把R7赋给ACC,如果直通过ACC传递返回效率会高很多,本身ACC的效率就比RX要高,这些可能是历史原因造成的.

使用特权

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

本版积分规则