4

コードのパフォーマンスについて質問があります。Cにポイントの構造体があるとしましょう:

typedef struct _CPoint
{
    float x, y;
} CPoint;

構造体を使用する関数。

float distance(CPoint p1, CPoint p2)
{
    return sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2));
}

この関数を#defineに置き換えるのが賢明なアイデアかどうか疑問に思いました。

#define distance(p1, p2)(sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2)));

関数のオーバーヘッドがないため、より高速になると思います。パフォーマンスを向上させるために、プログラム内の他のすべての関数にこのアプローチを使用する必要があるかどうか疑問に思っています。だから私の質問は:

コードのパフォーマンスを向上させるために、すべての関数を#defineに置き換える必要がありますか?

4

5 に答える 5

8

いいえ。認識されたパフォーマンスの違いに基づいて、マクロと関数の間で決定を下すことは決してありません。マクロに対する関数のメリットのみに基づいて評価する必要があります。一般的に機能を選択します。

マクロには、あなたを苦しめる可能性のある隠れた欠点がたくさんあります。適切な例として、ここでのマクロへの翻訳は正しくありません (または、少なくとも元の関数でセマンティクスが保持されていません)。マクロへの引数は、distanceそれぞれ 2 回評価されます。次の呼び出しを行ったと想像してください

distance(GetPointA(), GetPointB());

マクロ バージョンでは、各引数が 2 回評価されるため、実際には 4 つの関数呼び出しが発生します。関数distanceのままにしておくと、3 つの関数呼び出し (距離と各引数) だけになります。注:上記の計算では、両方のバージョンで同じであるため、sqrtとの影響は無視しています。pow

于 2011-10-13T16:25:16.920 に答える
3

次の 3 つのことがあります。

  • distance上記のような通常の機能
  • インライン関数
  • プリプロセッサ マクロ

関数はある種のタイプ セーフを保証しますが、各関数呼び出しでスタック フレームを使用する必要があるため、パフォーマンスの低下も招きます。インライン関数のコードは呼び出しサイトでコピーされるため、ペナルティは発生しませんが、コード サイズは増加します。マクロはタイプ セーフを提供せず、テキスト置換も伴います。

3 つすべてから選択して、通常はインライン関数を使用します。マクロは、非常に短く、この形式で非常に役立つ場合のみ ( hlist_for_eachLinux カーネルからのように)

于 2011-10-13T16:27:17.557 に答える
3

inlineマクロよりも関数をお勧めします。これにより、見苦しさを感じることなく、マクロの可能な限りのパフォーマンス上の利点が得られます。(マクロには、関数の一般的な置き換えとして非常に疑わしいものにするいくつかの落とし穴があります。特に、マクロ引数は使用されるたびに評価されますが、関数引数は「呼び出し」の前に一度ずつ評価されます。)

inline float distance(CPoint p1, CPoint p2)
{
    float dx = p2.x - p1.x;
    float dy = p2.y - p1.y;
    return sqrt(dx*dx + dy*dy);
}

(私も に置き換えたことに注意pow(dx, 2)してくださいdx * dx。2つは同等であり、乗算はより効率的である可能性が高いです。一部のコンパイラは、...への呼び出しを最適化しようとするかもしれませんpowが、それを何に置き換えるかを推測します。)

于 2011-10-13T16:28:34.367 に答える
3

Jared の言うとおりです。この特定のケースでは、pow呼び出しと呼び出しsqrtに費やされるサイクルは、への呼び出しに費やされるサイクルよりも 2 桁多くなりますdistance

小さなコードは短い時間に等しいと考える人がいます。そうではありません。

于 2011-10-13T16:29:14.180 に答える
1

かなり成熟したコンパイラを使用している場合、最適化がオンになっている場合、アセンブリレベルでこれを行うことが提案されます。

gcc の場合は -O3 または (「小さい」関数の場合) -O2 オプションでさえこれを行います。

詳細については、「-finline*」オプションについてhttp://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.htmlを参照してください。

于 2011-10-13T16:28:54.850 に答える