3
#include <iostream>
int foo() {
    std::cout<<"foo() is called\n";
    return 9;
}
int bar() {
    std::cout<<"bar() is called\n";
    return 18;
}
int main() {
    std::cout<<foo()<<' '<<bar()<<' '<<'\n';
}
// Above program's behaviour is unspecified
// clang++ evaluates function arguments from left to right: http://melpon.org/wandbox/permlink/STnvMm1YVrrSRSsB
// g++ & MSVC++ evaluates function arguments from right to left
// so either foo() or bar() can be called first depending upon compiler.

上記のプログラムの出力はコンパイラに依存します。関数の引数が評価される順序は規定されていませ。私がこれについて読んだ理由は、高度に最適化されたコードになる可能性があるからです。関数引数の評価の正確な順序を指定しないと、コンパイラは最適化されたコードを生成できませんか?

私の知る限り、評価の順序は、Java、C#、D などの言語で厳密に指定されています。

4

4 に答える 4

9

質問の前提全体が間違っていると思います:

C および C++ コンパイラが最適化されたコードを生成するのに役立つ関数引数の評価の正確な順序を指定しませんか?

コードの最適化に関するものではありません (ただし、それは可能です)。基礎となるハードウェアには特定の ABI 制約があるため、コンパイラにペナルティを課さないということです。

一部のシステムは逆順でスタックにプッシュされるパラメーターに依存し、他のシステムは順順に依存します。C++ は、あらゆる種類の制約を持つあらゆる種類のシステムで実行されます。言語レベルで命令を強制する場合、その命令を強制するために一部のシステムにペナルティを支払う必要があります。

C++ の第一のルールは、「使わなければお金を払う必要はない」です。したがって、順序を強制することは、C++ の主要なディレクティブに違反することになります。

于 2016-05-04T14:34:05.490 に答える
7

そうではありません。少なくとも、今日はそうではありません。たぶん、過去にそうでした。

C++17の提案では、関数呼び出しなどの左右の評価順序を定義することが提案operator<<されています。

その論文のセクション 7 で説明されているように、この提案は Windows NT カーネルをコンパイルしてテストされ、実際にいくつかのベンチマークで速度が向上しました。著者のコメント:

これらの結果は、オプティマイザーがまだ更新されていないことを認識して新しい評価ルールを利用し、関数呼び出しを左から右に評価することをやみくもに強制されるという最悪のシナリオに対するものであることは注目に値します。

速度向上の余地がさらにあることを示唆しています。

于 2016-05-04T14:42:38.237 に答える
5

評価の順序は、引数が渡される方法に関連しています。スタックを使用して引数を渡す場合、右から左に評価するとパフォーマンスが向上します。これは、引数がスタックにプッシュされる方法だからです。

たとえば、次のコードを使用します。

void foo(bar(), baz());

呼び出し規約が「スタックを介して引数を渡す」と仮定すると、C 呼び出し規約では、引数を最後のものからスタックにプッシュする必要があります。これにより、呼び出し先関数がそれを読み取るときに、最初の引数が最初にポップされ、可変個引数関数をサポートできるようになります。 . 評価の順序が左から右の場合、結果をbar()一時的に保存する必要があり、baz()呼び出した後、一時的なプッシュに続いて結果がプッシュされます。ただし、右から左への評価により、コンパイラは一時的な評価を回避できます。

引数がレジスタを介して渡される場合、評価の順序はそれほど重要ではありません。

于 2016-05-04T13:56:41.277 に答える
2

C および C++ 標準が関数引数の評価順序を指定しなかった本来の理由は、コンパイラにより多くの最適化の機会を提供することです。残念ながら、この理論的根拠は、これらの言語が最初に設計された時点での広範な実験によって裏付けられていません。しかし、それは理にかなっています。

この問題は、過去数年間に提起されてきました。Herb Sutter によるこのブログ投稿を参照し、コメントを確認することを忘れないでください。

提案P0145R1は、関数の引数と他の演算子の評価順序を指定する方がよいことを示唆しています。それは言います:

現在標準で指定されている式評価の順序は、アドバイス、一般的なプログラミング慣用句、または標準ライブラリ機能の相対的な安全性を損なうものです。トラップは、初心者や不注意なプログラマーだけのものではありません。ルールを知っていても、それらは無差別に私たち全員に影響を与えます。

これが最適化の機会にどのように影響するかについての詳細は、そのドキュメントで確認できます。

過去数か月間、この言語の変更が最適化、互換性、および移植性にどのように影響するかについて、非常に広範な議論がありました。スレッドはここから始まり、ここに続きます。そこには数多くの例があります。

于 2016-05-11T07:24:53.587 に答える