我怎样才能最小化这个程序的代码大小?

Posted

技术标签:

【中文标题】我怎样才能最小化这个程序的代码大小?【英文标题】:How can I minimize the code size of this program? 【发布时间】:2014-04-16 12:04:28 【问题描述】:

我有一些记忆问题。在这个函数中是否可以减少编译程序的内存?

它使用时间变量 hh,mm,ss.0 进行一些计算并返回取决于当前进度 (_SHOOT_COUNT) 的时间(在 millis 中)

unsigned long hour_koef=3600000L;
unsigned long min_koef=60000;

unsigned long timeToMillis(int* time)

  return (hour_koef*time[0]+min_koef*time[1]+1000*time[2]+100*time[3]);


float Func1(float x)

  return (x*x)/(x*x+(1-x)*(1-x));


float EaseFunction(byte percent,byte type)

  if(type==0)
    return Func1(float(percent)/100); 



unsigned long DelayEasyControl()


  long dd=timeToMillis(D1); 
  long dINfrom=timeToMillis(Din);
  long dOUTto=timeToMillis(Dout);
  if(easyINmode==0 && easyOUTmode==0) return dd;
  if(easyINmode==1 && easyOUTmode==0)
  
    if(_SHOOT_COUNT<duration) return (dINfrom+(dd-dINfrom)*EaseFunction(_SHOOT_COUNT*100/duration,0));
    else return dd;
   
  if(easyOUTmode==1)
  
    if(_SHOOT_COUNT>=_SHOOT_activation && _SHOOT_activation!=-1)
       
      if((_SHOOT_COUNT-_SHOOT_activation)<current_settings.delay_easyOUT_duration) return (dOUTto-(dOUTto-dd)*(1-EaseFunction((_SHOOT_COUNT-_SHOOT_activation)*100/duration,0)));
      else return dOUTto;
     
    else 
    
      if(easyINmode==0) return dd;
      else if(_SHOOT_COUNT<duration) return (dINfrom+(dd-dINfrom)*EaseFunction(_SHOOT_COUNT*90/duration,0));
      else return dd;
    
  

【问题讨论】:

我在这里看不到单个内存分配。 EaseFunction 是做什么的?您是如何得出此函数使用过多内存的结论的? 对不起,我的意思是编译后的程序大小)EaseFunction 看起来像这样float Func1(float x) return (x*x)/(x*x+(1-x)*(1-x)); float EaseFunction(byte percent,byte type) if(type==0) return Func1(float(percent)/100); 您应该编辑问题,以便其他人更容易找到和理解您的问题。 该代码看起来不大。您的目标是哪种机器/微控制器/环境? 你试过 gcc 的 -Os 选项吗(看看这里:gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)?您也可以尝试在编译后剥离您的二进制文件 (sourceware.org/binutils/docs-2.16/binutils/strip.html)。 【参考方案1】:

您提到要优化的是代码大小,并且您在 Arduino 克隆(基于 ATmega32U4)上执行此操作。

那些控制器不支持浮点的硬件,所以这一切都将在占用大量代码的软件中进行模拟。

尝试重写它来做定点运算,这样你会节省很多代码空间。

通过优化其他数据类型,您可能会看到微小的收益,即uint16_t 而不是long 可能足以满足某些值,并且将函数标记为inline 可以节省执行跳转所需的指令。当然,编译器可能已经内联了。

【讨论】:

是的!再次感谢 - 它有效)使用 FIXED 计算我节省了超过 2.5kB 的程序)#define FIXED_FBITS 8 #define FIXED_TO_INT(a) ((a) &gt;&gt; FIXED_FBITS) #define FIXED_FROM_INT(a) (int32_t)((a) &lt;&lt; FIXED_FBITS) #define FIXED_MAKE(a) (int32_t)((a*(1 &lt;&lt; FIXED_FBITS))) static int32_t FIXED_Mul(int32_t a, int32_t b) return(((int32_t)a*(int32_t)b) &gt;&gt; FIXED_FBITS); 【参考方案2】:

大多数编译器都有优化大小的选项,请先尝试。然后,您可以尝试一些 8 位 MCU 的编译器中提供的非标准 24 位浮点类型,例如 NXP's MRK III 或 MPLAB XC8

默认情况下,XC8 编译器使用 24 位浮点格式,它是 32 位格式的截断形式,具有 8 位指数但只有 16 位有符号尾数。

Understanding Floating-Point Values

这将大大减少浮点数学库的大小无需任何代码更改,但对于您的 MCU 而言它可能仍然太大。在这种情况下,您需要重写程序。最有效的解决方案是切换到fixed-point(A.K.A 缩放整数),如@unwind 所说,如果您不需要非常宽的范围。事实上,这比软件浮点解决方案要快得多,而且占用的 ROM 大小要少得多。上面的 Microchip 文档也提出了解决方案:

较大的 IEEE 格式允许精确的数字,涵盖要处理的大范围值。然而,这些格式需要更多的数据内存来存储这种类型的值,并且处理这些值的库例程非常大而且速度很慢。浮点计算总是比整数计算慢得多,应尽可能避免使用,尤其是在使用 8 位设备时。 page 表示您可以考虑的一种替代方案。

此外,您可以尝试将重复的表达式(如 x*x1-x)存储到一个变量中,而不是像 (x*x)/(x*x+(1-x)*(1-x)) 这样计算它们两次,如果编译器太笨,这会有所帮助。与easyINmode==0easyOUTmode==1相同...


其他一些事情:

ALL_CAPS 只能用于宏和常量 标识符以_ 开头,并且为图书馆保留大写字母。 C 也可以将它用于将来的功能,例如 _Bool_Atomic。见What are the rules about using an underscore in a C++ identifier?(Arduino 可能是 C++) 对于重复使用多次的东西,使用函数而不是宏,因为内联扩展每次使用都会占用一些空间

【讨论】:

以上是关于我怎样才能最小化这个程序的代码大小?的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能最小化和恢复灯箱上的功能..?

C语言 怎样设计一个比较3个数大小的程序,跪求~~~

如何最小化多个音频代码

我怎样才能让一个有角度的应用程序(嵌入在不同的网站上)一直跨越到页面的底部

两个 UIView 之外的最小矩形 - 目标 C

怎么将文件用7Z压缩到最小