2

次の (少し想像された) 例を考えてみましょう。

// a.cpp
int mystrlen(const char* a) {
   int l = 0;
   while (a[l]) ++l;
   return l;
}

// b.cpp
extern int mystrlen(const char*);
int foo(const char* text) {
   return mystrlen(text) + mystrlen(text);
}

mystrlen()副作用がなく、古い結果をmystrlen(text)2 回呼び出す代わりに再利用できることをコンパイラに伝えることができれば、非常に便利です。

それについてのドキュメントには何も見つかりません。restrictまたは、その差異の1つも機能していないようです。すべての最適化 (switch /Ox) をオンにした出力コードを見ると、コンパイラが実際に 2 つの呼び出しを生成していることがわかります。両方の機能を 1 つのモジュールに入れても、そうです。

これに対する解決策はありますか、またはVC ++に解決策がないことを誰かが確認できますか?

4

3 に答える 3

1

MSVC は pure/const 属性をサポートしておらず、それらをサポートする意図もありません。https://connect.microsoft.com/VisualStudio/feedback/details/804288/msvc-add-const-and-pure-like-function-attributesを参照してください。GCC や Clang などの他のコンパイラは、このような属性をサポートしています。また、さまざまなコンパイラでの pure/const 関数の属性も参照してください。

于 2015-07-07T14:31:20.673 に答える
0

あなたが探しているものはあなたを助けません。

一般に、関数に副作用がないと信じていても、コンパイラは呼び出しを省略できません。そのポインターはどこで手に入れましたか?シグナルハンドラは同じポインタにアクセスできますか? もしかして別スレ?コンパイラーは、ポインターが指すメモリーがその下から変更されないことをどのように認識しますか?

コンパイラーは、ポインターを介してフェッチされたものであっても、関数本体内の冗長なフェッチを頻繁に排除します。しかし、彼らができること、あるいはすべきことには限界があります。

ここでは、2 つの関数呼び出し間で内容の一貫性を維持する場所を知っているポインタを持っていると信じるようにコンパイラに求めています。それは多くの仮定です。確かに、ポインターを揮発性と宣言していませんが、それでも、多くの仮定があります。

ここで、スタックにバッファーがあり、それをその関数に 2 回続けて渡していた場合、コンパイラーは、ポインターを別の場所に渡していなければ、そのバッファーの内容が移動していないとかなり安全に想定できます。予期せぬときに、プログラム内のランダムな他のものによって変更されます。

例えば:

// b.cpp
extern int mystrlen(const char*);
int foo(int bar) {
   char number[20];
   snsprintf(number, 20, "%d", bar);
   return mystrlen(number) + mystrlen(number);
}

それがライブラリ関数であるという前提でコンパイラが行うことができる仮定を考えると、snprintf副作用がないことを宣言する方法があれば、コンパイラはnumberの 2 番目の呼び出しを省略することができます。mystrlenmystrlen

于 2017-03-19T00:05:53.333 に答える