コンパイラは、プログラムが実行される前に平方根がメモリ内のどこにあるかをどのように知っていますか?私は、アドレスがプログラムが実行される異なる毎回だろうと思ったが、これは動作します:それはアドレスがメモリ内の別のアドレスからの相対であるため、なぜ機能ポインタは `constexpr`ですか?
constexpr double(*fp)(double) = &sqrt;
cout << fp(5.0);
ですか? fp
の値が大きいため、私はそうは思わない:0x720E1B94。
コンパイラは、プログラムが実行される前に平方根がメモリ内のどこにあるかをどのように知っていますか?私は、アドレスがプログラムが実行される異なる毎回だろうと思ったが、これは動作します:それはアドレスがメモリ内の別のアドレスからの相対であるため、なぜ機能ポインタは `constexpr`ですか?
constexpr double(*fp)(double) = &sqrt;
cout << fp(5.0);
ですか? fp
の値が大きいため、私はそうは思わない:0x720E1B94。
コンパイラは、プログラムが実行される前に平方根がメモリ内のどこにあるかをどのように知っていますか?
ツールチェーンは、機能の配置場所を決定します。
このアドレスはメモリ内の別のアドレスとの相対値であるためですか?
生成されたプログラムがrelocatableまたはposition independentの場合は、そうです。プログラムがどちらのプログラムでもない場合、アドレスは絶対アドレスにすることもできます。
次回プログラムが実行されたときに、まったく同じメモリスポットが使用可能になるのはなぜですか?
メモリスペースがvirtualであるためです。
スペースは仮想ですが、今日でも[ASLR](https://en.wikipedia.org/wiki/Address_space_layout_randomization)もよく使用されています。 – Ruslan
コンパイル時に、コンパイラはsqrt
のアドレスを認識しません。しかし、コンパイル時には、ポインタのアドレスにアクセスするためのconstexpr関数ポインタを使って何もすることはできません。したがって、コンパイル時の関数ポインタは不透明な値として扱うことができます。
constexpr変数が初期化された後で変数を変更することはできないため、すべてのconstexpr関数ポインタを特定の関数の場所にまで煮詰めることができます。
あなたはこのようなものでした場合:コンパイラは正確に検出することができます
using fptr = float(*)(float);
constexpr fptr get_func(int x)
{
return x == 3 ? &sqrtf : &sinf;
}
constexpr fptr ptr = get_func(12);
get_func
は、特定のコンパイル時の値を返す関数。したがってget_func(12)
は&sinf
に減少します。したがって、&sinf
がコンパイルするものは、正確にはget_func(12)
にコンパイルされます。
* can * or * must *? – Deduplicator
@Deduplicator:両方。 –
これは、コンパイラが '&sinf'の値をどのように知っているかを説明していません。 @ hydeの答えだけでそのことが説明されています。 – fishinear
アドレス値はリンカーによって割り当てられているため、コンパイラは正確なアドレス値を認識しません。
cout << fp(5.0);
これは、正確なアドレスが解決された後に実行時に評価されるためです。
通常、コンパイル時にはわからないため、constexpr
ポインタの実際の値(アドレス)は使用できません。
言及ビャーネ・ストロヴストルップのC++プログラミング言語第4版:
10.4.5アドレス定数式
のような静的に割り当てられたオブジェクト(§6.4.2)のアドレス、グローバル変数は定数です。ただし、その値はコンパイラではなくリンカによって割り当てられるため、コンパイラはそのようなアドレス定数の値を知ることができません。これは、ポインタと参照型の定数式の範囲を制限します。たとえば:
constexpr const char∗ p1 = "asdf"; constexpr const char∗ p2 = p1; // OK constexpr const char∗ p2 = p1+2; // error : the compiler does not know the value of p1 constexpr char c = p1[2]; // OK, c==’d’; the compiler knows the value pointed to by p1
'constexpr const char * p3 = p1 + 2;'はわかります。 「p1 + 2」は、静的記憶期間を有するサブオブジェクトのアドレスを表す値であり、有効な定数式である。この場合、完全なオブジェクトの必要はありません。非タイプのテンプレート引数として使用することはできませんが、それは別の話です。私はこのような構造が邪魔になるような規格を見つけることはできません。これはC++ 11以降のバージョンに適用されます。私がテストしたすべてのコンパイラがそれを受け入れます。 [この回答](http://stackoverflow.com/a/17660391/4326278)も参照してください。 – bogdan
それは簡単です。
は、コンパイラは、このコードで呼ばれるアドレスを知っている方法を考えてみましょう:
puts("hey!");
コンパイラがputs
の場所のないアイデアを持っていない、それはまたそれのためのランタイム・ルックアップを追加しません(それはなるだろうそれは実際にクラスの仮想メソッドが必要とするものですが、パフォーマンスには悪いです)。ランタイム時に異なるバージョンのダイナミックライブラリを持つ可能性(正確に同じライブラリファイルであってもアドレス空間レイアウトのランダム化はもちろん)は、ビルド時にツールチェーンリンカーがそれを認識しないようにします。
したがって、コンパイルされたバイナリプログラムを起動するときにアドレスを修正するのは、dynamic linkerです。これは、の再配置と呼ばれます。
constexpr
:コンパイラは再配置テーブルにこのアドレスを使用するコード内のすべての場所を追加し、プログラムが開始するたびに動的リンカがそのジョブを実行します。
このジョブはコンパイラではありません。リンカーは物事がどこにあるのか把握します –
実際の住所ではありません – Arunmu
@EdHealそれはまだ実行前ですが、なぜその値がすべての実行で同じになるのかわかりません! – Coolwater