[英]optimizing a line of C code for 8 bit processor
我正在使用8位处理器,并且已经在C编译器中编写代码,现在超过140行代码只占用1200字节,而这条单行占用的字节超过200字节。 eeprom_read()
是一个函数,这个1000和100和10乘法应该有问题。
romAddr = eeprom_read(146)*1000 + eeprom_read(147)*100 +
eeprom_read(148)*10 + eeprom_read(149);
处理器是8位, romAddr
数据类型是int
。 有没有办法以更优化的方式编写这一行?
使用最多空间的东西可能是乘法的使用。 如果您的处理器缺少执行乘法的指令,则编译器必须逐步使用软件来执行此操作,这可能需要相当多的代码。
很难说,因为您没有指定目标处理器(或您正在使用的编译器)的任何内容。
一种方法可能是以某种方式尝试减少内联,因此可以重复使用乘以10的代码(在所有四个术语中使用)。
要知道是否属于这种情况,必须检查机器代码。 顺便说一下,使用十进制常量进行地址计算实际上很奇怪。
有时可以将乘法编译成一系列加法,是的。 您可以通过使用左移运算符来优化它。
A*1000 = A*512 + A*256 + A*128 + A*64 + A*32 + A*8
或者同样的事情:
A<<9 + A<<8 + A<<7 + A<<6 + A<<5 + A<<3
这仍然比单个“乘法”指令长一些,但是你的处理器显然没有它,所以这可能是下一个最好的事情。
你关注的是空间,而不是时间,对吧? 你有四个函数调用,每个函数都传递一个整数参数,然后乘以一个常量,然后加上。 就像第一个猜测一样,那可能是
eeprom_read
(6个字节) 让我们看看,6 + 2 + 6 + 4 + 6 + 4 + 6 + 4 + 6 + 2 + 6 =每次调用eeprom_read
约52个字节。 最后一次调用会更短,因为它不会成倍增加。
我会尝试不使用像146
这样的参数来调用eeprom_read
,而是使用(unsigned char)146
,并且乘以1000
而不是(unsigned short)1000
。 这样,您可以使编译器使用更短的指令,并且可能使用乘法指令而不是乘法函数调用。 此外,对eeprom_read
的调用可能会被宏观化为直接内存提取,从而节省了参数的推送,函数的调用以及堆栈调整。
另一个技巧可能是将四个产品中的每一个存储在一个局部变量中,并在最后将它们全部加在一起。 这可能会产生更少的代码。 所有这些可能性也会使它更快,更小,尽管你可能不需要关心它。
节省空间的另一种可能是使用循环,如下所示:
static unsigned short powerOf10[] = {1000, 100, 10, 1};
unsigned short i;
romAddr = 0;
for (i = 146; i < 150; i++){
romAddr += powerOf10[i-146] * eeprom_read(i);
}
这应该通过调用和乘法仅一次,加上循环指令而不是四个副本来节省空间。
在任何情况下,都可以使用编译器生成的汇编语言。
它非常非常依赖于编译器,但我建议你至少通过这种方式简化乘法:
romAddr = ((eeprom_read(146)*10 + eeprom_read(147))*10 +
eeprom_read(148))*10 + eeprom_read(149);
你可以把它放在一个循环中:
uint8_t i = 146;
romAddr = eeprom_read(i);
for (i = 147; i < 150; i++)
romAddr = romAddr * 10 + eeprom_read(i);
希望编译器应该认识到将16位值乘以10会更简单,而单独实现乘法1000和100则相比。
不过,我并不完全依赖编译器来有效地处理循环。
也许:
uint8_t hi, lo;
hi = (uint8_t)eeprom_read(146) * (uint8_t)10 + (uint8_t)eeprom_read(147);
lo = (uint8_t)eeprom_read(148) * (uint8_t)10 + (uint8_t)eeprom_read(149);
romAddr = hi * (uint8_t)100 + lo;
所有这些都是未经测试的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.