ホームページ  >  記事  >  バックエンド開発  >  「C プログラミング言語」の関数チェーンは指定されていない動作を示しますか?

「C プログラミング言語」の関数チェーンは指定されていない動作を示しますか?

Barbara Streisand
Barbara Streisandオリジナル
2024-10-23 18:19:25368ブラウズ

Does Function Chaining in

「C プログラミング言語」のコード スニペットは未定義の動作を示しますか?

問題の C コード (「」の第 4 版で Bjarne Stroustrup が提供) C プログラミング言語」では、関数チェーンを使用して文字列を変更します。

<code class="cpp">void f2() {
    std::string s = "but I have heard it works even if you don't believe in it";
    s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");

    assert(s == "I have heard it works only if you believe in it");
}</code>

このコードは、文字列 s を変更する replace() 操作のチェーンを示しています。ただし、このコードは、GCC、Visual Studio、Clang などのさまざまなコンパイラ間で異なる動作を示すことが観察されています。

分析

コードは単純に見えますが、不特定の順序が含まれます。特に関数呼び出しを伴う部分式の評価。 (すべての副作用は関数呼び出し内で発生するため) 未定義の動作は引き起こしませんが、未指定の動作は示します。

重要な問題は、s.find( などの部分式の評価順序です)。 "even") および s.find(" don't") は明示的に定義されていません。これらの部分式は、最初の s.replace(0, 4, "") 呼び出しの前後で評価でき、結果に影響を与える可能性があります。

コード スニペットの評価順序を調べると、次のようになります。

s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");

次の部分式が不定に順序付けされていることがわかります (括弧内の数字で示されています):

  • s.replace(0, 4, "") (1)
  • s.find("even") (2)
  • s.replace(s.find("even"), 4, "only") (3)
  • s.find(" しないでください") (4)
  • s.replace(s.find(" しない"), 6, "") (5)

括弧の各ペア内の式は順序付けされています (例: 2 が 3 の前にある) が、相互に異なる順序で評価することができます。具体的には、式 1 と 2 の間、および式 1 と 4 の間に不確定性があります。

コンパイラの違い

コンパイラの動作で観察された矛盾は、それぞれが選択した異なる評価順序に起因している可能性があります。コンパイラ。場合によっては、 replace() 呼び出しが期待どおりの動作をもたらす方法で評価されることもありますが、評価順序によって文字列が予期しない方法で変更される場合もあります。

例として、次のことを考えてみましょう。

  • Clang などの一部の実装では、replace(0, 4, "") は find("even") および find(" don't") より前に評価されます。これにより、後続の置換呼び出しが変更された文字列に対して動作し、正しい結果が得られるようになります。
  • GCC や Visual Studio などの他の実装では、find("even") と find(" don't") が使用されます。 replace(0, 4, "") の前に評価される場合があります。 find 呼び出しは元の変更されていない文字列を操作し、意図したものとは異なる位置を検索する可能性があるため、不正確な結果が生じる可能性があります。

指定された動作と指定されていない動作

次の点に注意することが重要です。このコードは、未定義の動作を呼び出すことはありません。未定義の動作には、通常、初期化されていない変数にアクセスしたり、境界外のメモリにアクセスしようとしたりすることが含まれます。この場合、すべての副作用は関数呼び出し内で発生し、コードは無効なメモリ位置にアクセスしません。

ただし、コードは指定されていない動作を示します。つまり、コードの正確な順序は部分式の評価は C 標準では定義されていません。これにより、コンパイラが異なると、同じプログラムを実行しても異なる結果が生じる可能性があります。

提案された変更

C 標準委員会はこの問題を認識し、式の評価順序を改良するための変更を提案しました。慣用的な C 。 C 20 の [expr.call]p5 に対する変更案では、「postfix-expression は、expression-list 内の各式およびデフォルト引数の前に順序付けされる」と指定されており、これにより、このコードでの指定されていない動作が排除されます。

以上が「C プログラミング言語」の関数チェーンは指定されていない動作を示しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。