为什么FreeBSD的memchr实现会在其条件下增加指针?

时间:2017-02-28 01:42:34

标签: c freebsd

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;

使用条件内联后增量是否对某些编译器/平台有一些优化好处?

2 个答案:

答案 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