POSIX标准中lfind函数的nelp参数为何未使用const限定符?
POSIX Issue 7(2018版)在<search.h>中定义的lfind函数原型如下:
void *lfind(const void *, const void *, size_t *, size_t, int (*)(const void *, const void *));
从LSEARCH(3P)手册页中能看到更清晰的参数命名:
void *lfind(const void *key, const void *base, size_t *nelp, size_t width, int (*compar)(const void *, const void *));
注意到nelp的类型是size_t*而非const size_t*。这一设计对lsearch来说是合理的——因为lsearch会在未找到元素时将其插入表中,因此需要更新*nelp的值。但lfind的行为明确是:
若条目被添加到表中,nelp指向的整数应递增。
lfind()函数与lsearch()等价,区别是未找到条目时不添加,返回空指针。
既然lfind不会插入元素,也就没有修改*nelp的需求,那这种设计是遗漏了const限定符,还是存在某些必须让lfind修改*nelp的场景?
编辑补充:有观点认为这是为了和lsearch保持接口一致性,这能解释为什么lfind用指针而非直接传size_t,但无法解释为什么base参数加了const而nelp没有——给nelp加上const并不会影响用户传递指针。
问题解答
这既不是必须修改*nelp的场景,也算不上严格意义的“遗漏限定符”,本质是历史接口设计中为一致性做出的妥协:
无实际修改需求:根据POSIX标准的明确定义,
lfind不会向目标表中添加任何元素,因此不存在任何需要修改*nelp的场景。标准中关于nelp递增的描述仅适用于lsearch,和lfind的行为完全无关。接口一致性的权衡:
lfind和lsearch作为同一系列的查找函数,早期设计时大概率直接复用了核心参数结构,为了让两个函数的接口签名更相似、降低使用者的学习成本,没有特意为lfind的nelp参数添加const修饰。这种“为了统一而牺牲严谨性”的做法,在C语言早期的标准库接口中并不少见。const修饰的合理性:你提到的
base加const而nelp不加的矛盾点确实存在——从语义上来说,lfind不会修改base指向的数组,也不会修改*nelp,所以nelp完全可以声明为const size_t*。之所以没这么做,纯粹是历史设计的惯性,而非技术上的必要。
内容的提问来源于stack exchange,提问作者anol

