【问题标题】:(Embedded) C: void function() or #define for low level register handling(嵌入式)C: void function() 或 #define 用于低级寄存器处理
【发布时间】:2019-07-18 08:58:55
【问题描述】:

我正在寻找有关嵌入式软件编码风格的答案。我的问题是我需要创建一个抽象层来处理低级寄存器操作。

有两种可能的方法,一种是基于#define 的,另一种是基于函数的。

在第一种方法中,我创建了简单的函数来处理注册操作。在本例中,我将一个微控制器端口设置为低电平状态。

static void breakLockNr_3()
{
    LATDbits.RD2 = 0;
}

在第二种方法中,我可以使用#defines 来定义相同的操作:

文件开头:

#define BREAK_LOCK_NR_3 LATDbits.RD2
#define BREAK_LOCK_NR_3_LOW 0

稍后在代码中:

BREAK_LOCK_NR_3 = BREAK_LOCK_NR_3_LOW

您认为哪种方法更易于使用并且更适合代码清理、速度和内存优化?

【问题讨论】:

  • 这是非常基于意见的。无论如何......这对我来说似乎是错误的:BREAK_LOCK_NR_3 = BREAK_LOCK_NR_3_LOW。我希望它是BREAK_LOCK_NR_3 = LOW 或者LOCK_NR_3 = BREAK
  • 我认为#define 方法在性能方面可能更好,因为如果您不内联它,您的函数方法会导致函数调用,恕我直言。如果您想使用第一个功能,我建议您将其内联
  • @Trickzter 静态函数是隐式内联的,您的编译器将在任何合理的优化级别上内联一个单行。
  • @Trickzter 编译器无论如何都可能内联函数调用
  • 哦,好的,谢谢你的信息!

标签: c function embedded styles


【解决方案1】:

如果您使用正确优化的编译器,该函数很可能会被转换为内联函数。在这种情况下,在速度或文本段空间方面没有性能影响。试试看你的编译器是否正在优化它。否则,您可以将函数显式定义为内联函数。

函数或宏是否合适取决于手头的应用程序以及其他几个设计决策。通常,与宏相比,函数更易于维护。所以宏应该谨慎使用。

有关为何应避免使用宏的更详细讨论,请参阅this

【讨论】:

  • 为什么你认为这种单行函数会比宏更易于维护?你能解释一下吗?
  • 宏在预处理步骤中通过文本处理工作。如果使用不当,您可能会搞砸。宏也无法调试。请参阅 [this] (pmihaylov.com/macros-in-c) 了解对此的详细讨论。鉴于在宏上使用内联函数没有开销,因此函数比宏更可取。但是,如果在宏上使用此类函数会产生开销(由于编译器的限制),那么宏可能是要走的路。
【解决方案2】:

如果你想公平比较,你的宏应该是这样的:

#define BREAK_LOCK_NB_3()   (LATDbits.RD2 = 0)

否则抽象级别不一样,因为在第二个示例中,您并没有真正抽象硬件。

我同意关于两种情况下性能相同的说法。

然而,更重要且您应该关注的是处理寄存器的方式。通常您设置或清除一位而不是整个寄存器,例如,使用掩码等。

【讨论】:

  • 但是,在这种情况下,我定义了一个类似函数的宏。其中,我认为这在 C 90 中很常见,其中内联函数尚未实现。
  • 是的。如果你多次调用这个函数/宏,那会更好,以防你的处理器进化,或者如果你发现你必须设置 2 位而不是 1 位,等等......
【解决方案3】:

正如之前的答案所表明的,现在尽可能地利用 C 的类型系统被认为是一种很好的做法。所以一般来说一切都带有类型>预处理器宏。在你的情况下,我更喜欢用“内联”注释的函数。我推荐这些关于该主题的最新链接:link1link2link3

【讨论】:

    【解决方案4】:

    第二种方法更可取,因为与函数执行(第一种方法)相比,它花费的时间更少,因为它会在预处理时删除具有实际值的宏。并且它将使代码易于理解。

    【讨论】:

    • 抱歉,这是错误的。该函数被声明为静态,这意味着它是隐式内联的,您的编译器将内联它。发出的二进制文件将是等效的。
    • @user6556709 有这方面的资料吗?我没有听说过这种行为,如果真的存在,我想提高我的知识。
    • @itachi Checkout godbolt.org 并使用不同的 -O 级别,即 -O0、-O1、-O2,... 你会看到内联会发生 - 除了 -O0跨度>
    • @itachi 没有标准化的优化。但是,由于所有常见的编译器,包括最专业的嵌入式编译器,都是这样做的,你可以假设它会以这种方式完成。如果您发现行为不同的编译器,请告诉我。 (行为不同是合法的,但内联是最便宜的优化之一,因此甚至可以在非常原始的编译器中实现。)
    • @itachi 您应该能够相信所有有效的 C 编译器的运算符优先级都是相同的。运算符优先级是标准的一部分。因此,看到两个编译器以不同的方式进行操作意味着(至少)其中一个存在错误......关于内联/优化以及标准 syas 的内容,我猜来自 user6556709 的评论涵盖了它
    猜你喜欢
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    相关资源
    最近更新 更多