使用宏来进行小型操作,这是一种很好的做法吗?

时间:2012-01-08 08:49:29

标签: c macros

我有一小段代码需要读取以32位整数进行bitpacked的4位值。因为我需要多次调用此操作,即使它很简单,我也需要最大速度。 我正在思考宏和内联函数,因此我创建了这个宏:

#define UI32TO4(x, p) (x >> ((p - 1) *4) & 15)

我有一个内联函数可以做同样的事情。

static inline Uint8 foo_getval(Uint32 bits, int pos){
    return (bits >> ((pos-1)*4)) & 15;
}

考虑到操作的简单性,并且已经为这个调用准备了值(因此不可能调用错误的类型,或者传递太大或者那些东西的值),那么最好的是什么呢?使用?或者,至少,对于其他可能在以后阅读/修改代码的人来说,最容易理解的是什么?

EDIT!忘了提,我正在使用C99。

3 个答案:

答案 0 :(得分:8)

功能更安全。您开发该代码时,您的假设值始终是“正确的”。你不知道是否有人(或你累了的时候)不会传递意外的值。

编译器在看到它有效时会进行内联。尽可能使用类型安全函数,只有在没有其他实际选择时才使用宏。

答案 1 :(得分:4)

我会使用内联函数,因为宏可能会导致不必要的副作用。如有必要,仅使用宏来保存输入。

如果宏名称与其他编译单元中的函数名称相同,则会出现奇怪的编译错误。这些问题很难找到,特别是如果宏在其他地方扩展并且没有发生错误。

此外,函数会警告您参数类型,并且不允许您为pos提供双精度。宏可以允许这样做。

答案 2 :(得分:2)

已经很晚了,而且我脾气暴躁(我之后可能会删除这篇文章),但我厌倦了听到反复鹦鹉学舌的相同论点(双重冗余):

  • Joachim Pileborg(上图)陈述“使用函数允许编译器做更好的类型检查”。这通常是 ,但我不相信。使用宏,编译器已经在其指尖处具有 all 可用的类型信息。功能只是破坏了这个。 (并且可能通过将寄存器推送到堆栈来破坏优化,但这是一个副问题。)

  • frast(上图)表示“宏可能会导致不必要的副作用”。是的 - 但是所以可以起作用。我认为规则始终使用UPPER_CASE用于宏,其中 具有函数语义。这条规则经常被打破。但它不适用于此:OP冗余地使用 大写函数语义。

但我建议稍微改进一下。 OP在整个宏周围放置了正确的括号,但每个参数周围也应该有括号:

   #define UI32TO4(x, p) ((x) >> (((p) - 1) * 4) & 15)

始终将宏args括在括号中,除非您正在进行字符串或标记连接等。

宏当然是危险的,但功能也是如此。 (而STL,越少越好。)