FreeBSD's generic implementation of memchr
:
void *
memchr(const void *s, int c, size_t n)
{
if (n != 0) {
const unsigned char *p = s;
do {
if (*p++ == (unsigned char)c)
return ((void *)(p - 1));
} while (--n != 0);
}
return (NULL);
}
对我来说,似乎不必要的复杂;最初的n != 0
检查do
- while
只是为了避免p
声明似乎完全没有意义。但是,我对循环体的原因特别感兴趣:
if (*p++ == (unsigned char)c)
return ((void *)(p - 1));
而不是更简单:
if (*p == (unsigned char)c)
return ((void *) p);
++p;
使用条件内联后增量是否对某些编译器/平台有一些优化好处?
答案 0 :(得分:3)
第一:这是纯粹的猜测。我没有编写这段代码,也无法验证我的猜测。
这两个版本的代码之间存在一个非常重要的语义差异:
// Version A
if (*p++ == (unsigned char)c)
return ((void *)(p - 1));
// Version B
if (*p == (unsigned char)c)
return ((void *) p);
++p;
在版本A中,增量在if
的代码块之前排序,而在版本B中,它在该块之后排序。
因此,在版本A中,增量代码将放置在可能从if
生成的分支指令之前。至少我们可以IMO假设这样一个相对直接的从C代码到代码编写时汇编的汇编(1988?)。
使用条件内联后增量是否有一些 某些编译器/平台的优化好处?
在分支之前获得增量允许对其分支指令具有delay slot的体系结构进行相对简单的优化:您可以将增量移动到该延迟槽而不是在那里使用NOP。
因此,版本A每次循环迭代需要比指令B少一个指令,代价是函数返回时的单个递减。这是一种(微观)优化。
答案 1 :(得分:2)
指针后增量的情况是允许时代的编译器(例如PCC)在DEC机器中使用自动增量寻址模式(如评论中的Mark Plotnick提到的那样)。
由于所有DEC机器都支持自动递增寻址,这种编码循环方式曾经非常普遍(顺便说一句,m68k支持相同的优化)。
另一方面,do-while
循环只是因为在naïf编译器上它往往会产生更好的代码,而不仅仅是为了避免设置p
。
。