0

GCC ドキュメントから:

多くの関数は、引数以外の値を調べず、戻り値以外には何の効果もありません。関数はグローバルメモリを読み取ることができないため、基本的に、これは上記の純粋な属性よりもわずかに厳密なクラスです。

const私の質問は、グローバル値がグローバル メモリとしてカウントされるかどうかです。そうだと思いますが、不変として明示的にマークした値が、ここで可能な最適化を無効にする可能性があるのは奇妙に思えます。

例えば:

int const ConstantModulusValue = 3;

int foo(int value) {
    return foo % ConstantModulusValue;
}

の使用はConstantModulusValue、私の理解では、この関数をマークしてはならないことを意味しますが、これもconst奇妙に思えます。これをマークすることには危険がありconstますか?

4

1 に答える 1

1

これらの属性により、コンパイラは、実装方法を知らなくても関数の呼び出しを省略しても安全かどうかを知ることができます。

pure 属性は基本的に、関数の結果が関数の引数とグローバルな状態にのみ依存することを示しています。さらに、関数自体はグローバル状態を変更しません。

純粋な関数を 2 回呼び出すと、同じ結果が返されることが保証されます。ただし、呼び出し間でグローバルに表示される状態を変更すると、保証は保持されなくなります。

const 属性は、グローバル状態が変更された場合でも、関数が同じ結果を返す必要があるという点でより強力です。したがって、より多くの場合に const 関数への冗長な呼び出しを最適化しても安全です。

状態が変化しないことを保証できる場合、グローバル状態の読み取りは問題になりません (グローバルを const としてマークしても常にそれが保証されるわけではないことに注意してください)。

例として、次のプログラムを考えてみましょう。

int foo(int) __attribute__((pure));
int bar(int) __attribute__((const));
void unknown();

int test1(int a)
{
    int x = foo(a);
    int y = foo(a);
    return x + y;
}

int test2(int a)
{
    int x = bar(a);
    int y = bar(a);
    return x + y;
}

int test3(int a)
{
    int x = foo(a);
    unknown();
    int y = foo(a);
    return x + y;
}

int test4(int a)
{
    int x = bar(a);
    unknown();
    int y = bar(a);
    return x + y;
}

gcc 4.8.1 でコンパイルしてアセンブリを分析すると、test1() と test2() の両方がそれぞれの関数を 1 回だけ呼び出してから、結果を 2 倍することがわかります。test3() は 3 回の呼び出しを行います - foo への 2 回の呼び出しと unknown への 1 回の呼び出し。test4() は、bar() の呼び出しに続いて unknown() の呼び出しを行い、bar() の結果を 2 倍して返します。

この動作は上記の説明と一致します。unknown() はグローバル状態を変更できるため、コンパイラは foo() への余分な呼び出しを省略できませんが、bar() への余分な呼び出しを省略できます。

于 2014-02-10T02:51:10.553 に答える