【问题标题】:Replacing repeated lines of code with a function用函数替换重复的代码行
【发布时间】:2014-05-08 10:44:37
【问题描述】:

我从事嵌入式 C 的工作,并正在尝试重构代码以提高可读性并优化我项目中使用的 ROM。

我有这 3 行代码在 switch-case 中重复多次,以更新特定屏幕名称上的特定编辑框。

EbSetText 和 SetState 是预定义的图形库函数。

sprintf(Screen1_Editbox1_Text,"%04d",GetHV(0));
EbSetText((EDITBOX *)GOLFindObject(ID_Screen1_Editbox1), Screen1_Editbox1_Text);
SetState(GOLFindObject(ID_TestProbe_HVEb01), EB_DRAW);

有些代码是这样重复的:

EbSetText((EDITBOX *)GOLFindObject(ID_Screen1_Editbox1), "Text to output");
SetState(GOLFindObject(ID_TestProbe_HVEb01), EB_DRAW);

对于存在的各种文本框和字符串/缓冲区输入,上述代码片段重复了 120 次。它主要损害了我的代码的可读性,并且我的 ROM 接近 90%。

我正在考虑用实用函数替换它以包含上述所有逻辑。

SetTextofEditBox(Screen1_Editbox1_Text,ID_Screen1_Editbox1);

用单一的实用函数代替它在这里有什么好处吗?

【问题讨论】:

  • 宏是否对你有用。

标签: c optimization refactoring embedded readability


【解决方案1】:

正如 unwind 所说:函数调用可能比你现在拥有的更昂贵。当然,庞大的函数和重复相同的代码会导致代码丑陋,更难维护,因此更容易出错。

我个人会考虑使用inline 函数,让编译器决定代码是否应该在本地执行,或者函数调用确实是更好的选择。
或者,如果您愿意,也可以简单地使用宏。

inline 通常被认为是更好的选择,看看你发布的那些微小的 sn-ps 代码,我想说你也应该在这里使用内联函数。
请记住,inline 留给编译器来决定是否内联函数,所以如果 - 经过一些严肃且具有代表性的测试 - 你觉得函数 应该 总是内联,并且您正在使用 gcc,您可以使用 GCC always_inline 属性:

__attribute__((always_inline)) void your_inline_func(void *x, const char *y){}

如果无法说服您的编译器始终如此轻松地内联函数,那么您将不得不重新使用宏。请注意:宏不是类型安全的,并且可能会产生副作用:必须进行彻底的测试。

根据您发布的 2 条语句,一种使您的代码更“数据驱动”的方法,正如 unwind 建议的那样:

const char *txt_argument;
//and for any other argument you might need, too:
EDITBOX *edit = NULL;
//possibly add SetState's  arguments
switch(foo)
{
    case bar:
        txt_argument = Screen1_Editbox1_Text;
        edit = (EDITBOX *)GOLFindObject(ID_Screen1_Editbox1);
        break;
    case zar:
        txt_argument = "Text to output";
        edit = (EDITBOX *)GOLFindObject(another_editbox);
        break;
}
EbSetText(edit, txt_argument);

这并没有真正减少您拥有的代码量,但确实可以更轻松地监督 switch 实际在做什么。

如果您正在研究如何(进一步)优化这一大型 switch 语句,那么您可以查看 nesting the switch cases。这很可能没有什么影响,但对于某些编译器,在某些情况下,它可以有所作为。

如果您有 120 个案例,请尝试查看是否不能将它们分成 2 或 3 组:非常常见的、可能的和很少发生的案例。最常见的情况出现在主要的switch 中,然后default 包含另一个列出不太常见情况的开关,而那里的默认情况又是处理罕见情况的开关。
嵌套当然容易出现乱码,如果你愿意,可以简单地将default: switch位替换为一系列更短的switch-es,然后再回车……

【讨论】:

  • 嵌入式编译器通常喜欢执行大量的内联,所以这是一个很好的解决方案。
  • @Lundin:嗯,一如既往:你不能真的 100% 确定,除非你先尝试'n test,当然......但嵌入式开发支持内联是有道理的,肯定的
【解决方案2】:

也许吧。很难确定,这取决于额外函数调用的开销是否会大于本地工作的开销。

您可以尝试将其拆分并使其更加“数据驱动”,即安排代码以便始终在 switch 之后调用 EbSetText()SetState() 函数,但将它们的参数放入每个case 正确设置的变量。

【讨论】:

  • 好主意,但我在 switch-case 中有很多 if 条件。
  • @Gopi Fine ...但是您为什么要接受实现这一点的答案呢? :)
  • 我也可以接受你的 :) 吗?我想放弃投票,但我没有这样做的声誉:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
  • 2014-03-07
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 2015-10-30
相关资源
最近更新 更多