プログラミング、リファクタリング、そしてすべてにおける究極の疑問: No. 18

同カテゴリーの次の記事

インテル® C++ コンパイラーでサポートされる C++17 の機能

この記事は、インテル® デベロッパー・ゾーンに公開されている「The Ultimate Question of Programming, Refactoring, and Everything」の日本語参考訳です。


18. ある言語の知識は必ずしも別の言語に適用できるとは限らない

Putty プロジェクトから抜粋した以下のコードについて考えてみます。非効率的なコードは、次の PVS-Studio 診断によって検出されます。

V814 Decreased performance. Calls to the ‘strlen’ function have being made multiple times when a condition for the loop’s continuation was calculated. (V814 パフォーマンス低下。ループの継続条件の計算時に ‘strlen’ 関数が複数回呼び出されました。)

static void tell_str(FILE * stream, char *str)
{
  unsigned int i;
  for (i = 0; i < strlen(str); ++i)
    tell_char(stream, str[i]);
}

説明

これは実際にはエラーではありませんが、strlen() 関数がループの各反復で呼び出されているため、長い文字列を扱う場合には非常に非効率的です。

通常、このようなエラーは、Pascal (または Delphi) での開発経験があるプログラマーが記述したコードで見られます。Pascal では、ループの終了条件の評価が一度しか計算されないため、このようなコードが非常に一般的です。

Pascal コードの例を見てみましょう。pstrlen() が一度だけ呼び出されているため、called は一度だけ出力されます。

program test;
var
  i   : integer;
  str : string;

function pstrlen(str : string): integer;
begin
  writeln('called');
  pstrlen := Length(str);
end;

begin
  str := 'a pascal string';
  for i:= 1 to pstrlen(str) do 
    writeln(str[i]);
end.

効率良いコード

static void tell_str(FILE * stream, char *str)
{
  size_t i;
  const size_t len = strlen(str);
  for (i = 0; i < len; ++i)
    tell_char(stream, str[i]);
}

推奨事項

C/C++ では、ループの終了条件が各反復で再計算されます。そのため、非効率な遅い関数の呼び出しを終了判定に含めることは、特にループに入る前にそれを一度計算すれば済む場合、良いアイデアとは言えません。

一部のケースでは、コンパイラーはこのような strlen() を含むコードを最適化できる可能性があります。例えば、ポインターが常に同じ文字列リテラルを参照する場合などです。しかし、それを期待すべきではありません。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事

  • Parallel Universe マガジンParallel Universe マガジン Parallel Universe へようこそ。 米国インテル社が四半期に一度オンラインで公開しているオンラインマガジンです。インテルの技術者によるテクノロジーの解説や、最新ツールの紹介など、並列化に関する記事を毎号掲載しています。第1号からのバックナンバーを PDF 形式で用意しました、ぜひご覧ください。 12 […]
  • 比較関数の罠比較関数の罠 この記事は、インテル® デベロッパー・ゾーンに公開されている「The Evil within the Comparison Functions」の日本語参考訳です。 この記事の PDF […]
  • ファクトシート: oneAPIファクトシート: oneAPI この記事は、インテル ニュースルームに公開されている「Fact Sheet: oneAPI」の日本語参考訳です。 この記事の PDF 版はこちらからご利用になれます。 oneAPI とは? oneAPI […]
  • 並列プログラミングにおけるロックの効率的な使用並列プログラミングにおけるロックの効率的な使用 この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Using Locks Effectively in Parallel Programming […]
  • マルチスレッド開発ガイド: 4.6 インテル® Parallel Composer を利用して並列コードを開発するマルチスレッド開発ガイド: 4.6 インテル® Parallel Composer を利用して並列コードを開発する コードの並列化にはさまざまな手法があります。この記事では、インテル® Parallel Composer で利用可能な手法の概要を説明し、各手法の主な長所を比較します。インテル® Parallel Composer は Windows* 上の C/C++ を使用した開発のみを対象としていますが、これらの手法の多くは Fortran や […]