我在库API中定义了一个实用程序结构,它有四个字段,都是数字计数器。
typedef struct {
size_t bytes;
int codepoints;
int graphemes;
int columns;
} TickitStringPos;
我想提供一些实用程序来轻松处理这些结构。我可以将这些实现为(静态内联)函数,例如
static inline void tickit_stringpos_zero(TickitStringPos *pos) {
pos->bytes = pos->codepoints = pos->graphemes = pos->columns = 0;
}
static inline void tickit_stringpos_limit_columns(TickitStringPos *pos, int columns) {
pos->bytes = pos->codepoints = pos->graphemes = -1;
pos->columns = columns;
}
TickitStringPos here, limit;
tickit_stringpos_zero(&here);
tickit_stringpos_limit_columns(&limit, 20);
或者我可以将这些实现为宏,例如
#define TICKIT_STRINGPOS_ZERO(pos) do {
(pos).bytes = (pos).codepoints = (pos).graphemes = (pos).columns = 0;
} while(0);
#define TICKIT_STRINGPOS_LIMIT_COLUMNS(pos,_columns) do {
(pos).bytes = (pos).codepoints = (pos).graphemes = -1;
(pos).columns = _columns;
} while(0);
TickitStringPos here, limit;
TICKIT_STRINGPOS_ZERO(here);
TICKIT_STRINGPOS_LIMIT_COLUMNS(limit, 20);
我应该考虑如何权衡这两种方法?每种方法都可能同样强大和灵活,但是出于某种原因,一种方法是否特别可取?
首选函数而不是宏,原因很简单,它们为您提供与宏不同的类型安全性。
此外,使用函数,您不必像宏那样处理任何副作用。
至于正在inline
的函数,它只是向编译器表明您希望它不绑定编译器以使函数inline
,但是任何现代编译器都可以轻松完成所需的工作。
正如 Als 所说,我认为出于维护原因,当存在这种可能性时应该使用函数。由于它们是内联的,因此不会造成性能损失。保存常量的宏,或者可能(非常)小的计算。
(注意:inline 关键字使函数就地替换,从而节省了上下文切换开销,但引入了空间问题。除非你想给速度留出空间,否则你也可以使用常规功能)
是在编译器范围之外(之前)评估的,这是反对这些宏的主要论点(第二个大多数时候它们只是不必要的)。你可以在这里找到Bjarne Stroustrup本人的一个很好的解释。