33

他のプリプロセッサ定数を使用して操作を実行する#defineを作成した場合、実行時にマクロが表示されるたびに最終値が計算されますか?これはコンパイラの最適化に依存しますか、それとも標準でカバーされていますか?

例:

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                TIMERB_1_S / 10

TIMER_100_MSマクロを使用するたびに、実行時に32768/10の操作が発生します

次のことは避けたいと思います。

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                3276

概要

コンパイラーは、コンパイル時に配列サイズなどを計算するために必要であるため、定数積分式を評価できる必要があります。ただし、標準では、「できる」(「しなければならない」ではなく)としか書かれていません。したがって、脳死したコンパイラだけがコンパイル時に定数積分式を評価しませんが、型にはまらないコンパイラのアセンブリ出力を簡単にチェックすると、それぞれのケースが検証されます。

4

9 に答える 9

35

マクロは単なるテキスト置換であるためTIMER_100_MS、プログラムでの書き込みの例では、 32768 / 10.

したがって、問題は、コンパイラが32768 / 10定数整数式である をいつ評価するかです。ここで標準が特定の動作を必要とするとは思いませんが (実行時とコンパイル時の評価は事実上区別できないため)、中途半端なコンパイラはコンパイル時にそれを評価します。

于 2009-01-12T17:57:55.900 に答える
13

最適化されることを保証する標準を知りません。プリプロセッサは TIMER_100_MS を 32768/10 に置き換えます。これは、gcc -c を実行することで確認できます。コンパイラがさらに最適化しているかどうかを確認するには、gcc -S を実行してアセンブラをチェックアウトします。gcc 4.1 では、最適化フラグがなくても、コンパイル中に定数に削減されます。

#include <stdlib.h>
#include <stdio.h>

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                TIMER_1_S / 10

int main(int argc, char **argv)
{
  printf("%d\n", TIMER_100_MS);

  return(0);
}

gcc -S test.c
cat test.s

...
    popl    %ebx
    movl    $3276, 4(%esp)
    leal    LC0-"L00000000001$pb"(%ebx), %eax
    movl    %eax, (%esp)
    call    L_printf$stub
...
于 2009-01-12T17:57:09.443 に答える
9

TIMERB_100_MSマクロを使用するたびに、実行時に操作 32768 / 10 が発生しますか?

を使用するコード内のすべての場所は、プリプロセッサによってTIMERB_100_MS置き換えられます。32768 / 10

その式がさらに最適化される (定数に評価される) かどうかは、コンパイラ次第です。

于 2009-01-12T17:56:30.303 に答える
8

皆さん、この変換は「コンスタント フォールディング」と呼ばれ、ほとんどの学生コンパイラでさえそれを行っています。あなたや大学のルームメイト以外の誰かが作成したコンパイラーがあり、静的に型付けされた言語をコンパイルしている限り、最適化を有効にしなくても信頼できます。の意味を変更することが許可されている風変わりな動的言語を扱っている場合は、別の問題です/

于 2009-01-13T06:23:05.197 に答える
0

コンパイラはコンパイル時に浮動小数点数を操作できません。コンパイル時に 3276 の値に満足している場合は問題ありませんが、コンパイラがコンパイル時にこれを浮動小数点精度で評価する方法はありません。浮動小数点数を最適化すると、数式で予期しない結果が生じる可能性があるため、浮動小数点数はコンパイラにとって最適化するにはトリッキーすぎます。そのため、適切なコンパイラ (gcc バージョン、clang バージョン、msvc バージョン、icc バージョン) は、それを単純化することはありません。 3276.8 、物語の終わり。

そして、あなたの質問の他の部分では、マクロ展開ごとに評価されるかどうか尋ねました。繰り返しますが、3276 の値で問題ない場合、答えはノーです。コンパイラ、最適化レベル、およびバックグラウンドに依存し、定数テーブルに配置するか、コードにインライン化することができます。マクロ展開ごとに実行時に同じ式を計算することは決してありません。繰り返しになりますが、浮動小数点の精度を 3276.8 にしたい場合は、その式が実行時にマクロ展開ごとに評価されます。

コンパイルと最適化の詳細については、こちらをご覧ください: http://www.agner.org/optimize/#manuals

于 2016-06-24T09:54:48.500 に答える
-4

コンパイル時。これは言語標準であり (常にそうでした)、コンパイラーには依存しません。

編集

コメンターは参照を求めました-「Cプログラミング言語」第2版の付録A12.3(p。229)からの引用:

フォームの制御行

#define identifier token-sequence 

プリプロセッサに、識別子の後続のインスタンスを指定されたトークンのシーケンスで置き換えさせます。roken シーケンスの前後の空白は破棄されます

編集終了

于 2009-01-12T17:55:44.797 に答える