我有一小段代码需要读取以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。
答案 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,
越少越好。)