3

C のスキルを磨くために、eglibc のソース コードをダウンロードしたところ、strncpy に出会いました。彼が n<=4 のケースを区別して 4 つのテストを行った理由がわかりません。

int
STRNCMP (const char *s1, const char *s2, size_t n)
{
  unsigned char c1 = '\0';
  unsigned char c2 = '\0';

  if (n >= 4)
    {
      size_t n4 = n >> 2;
      do
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0' || c1 != c2)
        return c1 - c2;
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0' || c1 != c2)
        return c1 - c2;
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0' || c1 != c2)
        return c1 - c2;
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0' || c1 != c2)
        return c1 - c2;
    } while (--n4 > 0);
      n &= 3;
    }

  while (n > 0)
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0' || c1 != c2)
    return c1 - c2;
      n--;
    }

  return c1 - c2;
}

私が知らないメモリレイアウトと関係があるかもしれません、私に教えてください。

4

1 に答える 1

6

展開されたループです。バイナリを少し大きくする代わりに、比較する 4 バイトごとに 3 つの減分、3 つの分岐、および 3 つの条件を排除することで、文字列の比較を高速化します。

ダフのデバイスと同じ手法を使用することで、最適化をさらに一歩進めた可能性もありますが、これが実際に高速になるかどうかは明らかではありません. リンク先のページから、

この残りの自動処理は、すべてのシステムとコンパイラで最適なソリューションではない可能性があります。場合によっては、実際には 2 つのループの方が高速な場合があります (メイン コピーを実行する 1 つのループをアンロールし、残りを処理する 2 番目のループ)。問題は、コンパイラがデバイスを正しく最適化する能力にあるようです。また、一部のアーキテクチャでは、パイプライン処理と分岐予測に干渉する可能性があります。Duff のデバイスの多数のインスタンスがバージョン 4.0 の XFree86 サーバーから削除されたとき、パフォーマンスが向上し、実行可能ファイルのサイズが大幅に縮小されました。したがって、このコードの使用を検討する場合は、いくつかのベンチマークを実行して、ターゲット コンパイラを使用して、ターゲット アーキテクチャ、ターゲット最適化レベルで実際に最速のコードであることを確認することをお勧めします。

于 2016-05-04T21:44:00.840 に答える