0

ideone.comで入手可能な例:

int passByConstPointerConst(MyStruct const * const myStruct)
int passByValueConst       (MyStruct const         myStruct)

どちらも渡された MyStruct の内容を実際にコピーしないように、コンパイラが上記の 2 つの関数を最適化すると思いますか?

多くの最適化に関する質問が個々のコンパイラと最適化設定に固有であることは理解していますが、単一のコンパイラ用に設計することはできません。代わりに、コピーを避けるためにポインターを渡す必要があるかどうかについて、一般的な期待を持ちたいと思います。コンパイラを使用して最適化を処理できるようconstにする (構成した後) ことは、より良い選択であり、より読みやすく、エラーが発生しにくいコードになるようです。

ideone.comの例の場合、コンパイラは明らかにデータを新しい場所にコピーしています。

4

3 に答える 3

1

このトピックは、comp.lang.cFAQで取り上げられています。

http://c-faq.com/struct/passret.html

大きな構造体が値渡しされる場合、これは通常、コピーではなくオブジェクトのアドレスを実際に渡すことによって最適化されます。次に、呼び出し先は、コピーを作成する必要があるかどうか、または単に元のオブジェクトを操作できるかどうかを判断します。

パラメータの const 修飾子は違いはありません。型の一部ではありません。それは単に無視されます。つまり、これら 2 つの関数宣言は同等です。

int foo(int);
int foo(const int);

宣言では const を省略できますが、定義では const を省略でき、その逆も可能です。呼び出しの最適化はconst、宣言でこれに依存することはできません。これconstは、オブジェクトが値渡しされるというセマンティクスを作成するものではないため、元のオブジェクトを変更することはできません。

最適化ではセマンティクスを維持する必要があります。オブジェクトのコピーが実際に渡されたかのように見える必要があります。

コピーが渡されなかったと判断できる方法は 2 つあります。もう 1 つの方法は、アドレスを比較することです。例えば:

 int compare(struct foo *ptr, struct foo copy);

内部compareでは、 のアドレスを取得して、copyそれが と等しいかどうかを確認できますptr。これを行ったにもかかわらず最適化が行われた場合、それは私たちに明らかになります。

于 2012-11-16T17:46:53.253 に答える
1

最初のケース (const ポインターを const に渡す) では、コピーは行われません。

2 番目のケースでは、コピーが発生し、オブジェクトのアドレスが取得され、省略記号を介して関数に渡され、コンパイラの観点から、他の理由がなければ、それが最適化されるとは思わないでしょう。関数がそのポインターで何をするか誰が知っていますか?

より一般的に言えば、値による呼び出しを参照による呼び出しに変更することは、コンパイラが行うことではないと思います。参照によるコピーが必要な場合は、自分で実装してください。

理論的には、関数を参照渡しに変換できることをコンパイラが検出できる可能性はありますか? はい; C標準には、できないとは書かれていません..

なぜあなたはこれについて心配しているのですか?パフォーマンスを懸念している場合、プロファイリングにより、値によるコピーがソフトウェアの重大なボトルネックであることがわかりましたか?

于 2012-11-16T17:30:30.160 に答える
1

2 番目の宣言は、実際には、渡された構造体のコピーを受け取るためのユーザーによる直接の要求です。

constmodifier は、ローカル コピーに加えられた変更の可能性を排除しますが、コピーのすべての理由を排除するわけではありません。

まず、コピーはそのアドレス ID を維持する必要があります。つまり、2 番目の関数内で、式は他のオブジェクトのアドレスとは異なる&myStruct値を生成する必要があります。もちろん、スマート コンパイラは、オブジェクトのアドレス ID に依存する状況を検出できます。MyStruct

第二に、エイリアシングは別の問題を引き起こします。プログラムにグローバル ポインターがMyStruct *global_structあり、2 番目の関数内で誰かが*global_struct. *global_struct引数として関数に渡されたものと同じ構造体オブジェクトである可能性があります。コピーが作成されていない場合、加えられた変更*global_structは local パラメータを介して表示されますが、これは災害です。エイリアシングの問題は、コンパイル時に解決するのがはるかに困難 (そして一般的には不可能) です。そのため、コンパイラは通常、コピーを最適化できません。

したがって、要求に応じて、コンパイラがコピーを実行することを期待しています。

于 2012-11-16T18:03:37.023 に答える