このコードを検討してください。
#define A 5
#define B 3
int difference = A - B;
「差分」の値はコンパイル時に「2」としてハードコードされていますか、それとも実行時に計算されますか?
このコードを検討してください。
#define A 5
#define B 3
int difference = A - B;
「差分」の値はコンパイル時に「2」としてハードコードされていますか、それとも実行時に計算されますか?
およびマクロは少し気を散らすものですA
。B
これ:
#define A 5
#define B 3
int difference = A - B;
これとまったく同じです:
int difference = 5 - 3;
後者について説明しましょう。
5 - 3
は定数式です。これは、「実行時ではなく変換中に評価できるため、定数が存在する可能性のある任意の場所で使用できる」という式です。これは*整数定数式でもあります。たとえば、ケースラベルは整数定数式である必要があるため、次のいずれかを記述できます。
switch (foo) {
case 2: /* this is a constant */
...
}
またはこれ:
switch (foo) {
case 5 - 3: /* this is a constant expression */
...
}
ただし、定義では、翻訳中に評価できると言っているのであって、評価しなければならないということではないことに注意してください。定数式を必要とするコンテキストがいくつかあり、それらのコンテキストでは、式はコンパイル時に評価される必要があります。
difference
しかし、それが何らかの関数内で宣言されていると仮定すると、初期化子はそれらのコンテキストの1つではありません。
(無料であっても)支払う価値のあるコンパイラは、コンパイル時にに縮小5 - 3
され、値をに格納するコードを生成します。ただし、そうする必要はありません。C標準は、プログラムの動作を指定します。その動作をどのように実装する必要があるかは指定されていません。ただし、使用しているコンパイラはすべて。に置き換えられると想定しても問題ありません。2
2
difference
5 - 3
2
あなたが書いたとしても:
int difference = 2;
コンパイラは、値5
をレジスタにロードし、そこから減算し、3
レジスタの内容をに格納するコードを合法的に生成できますdifference
。それはばかげたことですが、言語標準はそれを除外していません。
最終結果がdifference
値を持つものである限り2
、言語標準はそれがどのように行われるかを気にしません。
一方、あなたが書く場合:
switch (foo) {
case 5 - 3: /* ... */
case 2: /* ... */
}
次に、コンパイラーはエラーを診断できるように結果を計算する必要があります(同じ値を持つ2つのケースラベルを持つことはできません。
最後に、difference
ファイルスコープ(関数の外部)で定義する場合、初期値は一定である必要があります。ただし、その場合の本当の違いは5 - 3
、コンパイル時に評価されるかどうかではなく、非定数式の使用が許可されるかどうかです。
参考:2011 C規格の最新ドラフトはN1570(大きなPDF)です。定数式については、セクション6.6で説明します。
標準では、この種のことは指定されていません。このような潜在的な最適化については何も述べていません (正当な理由があります。標準は実装ではなくセマンティクスを定義します)。
コンパイラの逆アセンブリを調べてみませんか? それはあなたに決定的な答えを与えるでしょう。
...
では、そうしましょう。
VC++ 10 からの出力は次のとおりです。
#include <iostream>
#define A 5
#define B 3
int main() {
int x = A - B;
std::cout << x; // make sure the compiler doesn't toss it away
010A1000 mov ecx,dword ptr [__imp_std::cout (10A2048h)]
010A1006 push 2
010A1008 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]
return 0;
010A100E xor eax,eax
ご覧のとおり、 の出現をx
静的な値 2 に置き換え、 の呼び出しのためにスタックにプッシュしましたcout
。実行時に式を評価しませんでした。