1

プリプロセッサでプリコンパイル計算を行うためにBOOST_PPを使用しています。私は、コードサイズが非常に重要なアプリケーションに焦点を当てています。(したがって、コンパイラーがそうすべきである、または通常そうするべきであるとは言わないでください。コンパイル時に実行されるものと生成されるコードを制御する必要があります)。ただし、整数定数と変数の両方に同じ名前のマクロ/関数を使用できるようにしたいと思います。ささいな例として、私は持つことができます

#define TWICE(n) BOOST_PP_MUL(n,2)
//.....
// somewhere else in code
int a = TWICE(5);

これは私が望んでいることを行い、

int a = 10;

コンパイル時。

でも、

int b = 5;
int a = TWICE(b);

これは前処理する必要があります

int b = 5;
int a = 5 * 2;

もちろん、私は次のような従来のマクロを使用してそうすることができます

#define TWICE(n) n * 2

しかし、整数定数に対して私が望んでいることは実行されません(コンパイル時にそれらを評価します)。

だから、私の質問は、引数がリテラルか変数かをチェックしてから、異なる定義を使用するトリックがありますか?つまり、次のようなものです。

#define TWICE(n) BOOST_PP_IF( _IS_CONSTANT(n), \
                              BOOST_PP_MUL(n,2), \
                              n * 2 )

編集:それで、私が本当に求めているのは、コンパイル時に何かが利用可能な定数であるかどうかを確認する方法です。したがって、BOOST_PP_関数の適切な引数です。これは、ほとんどの人がプリプロセッサや一般的なプログラミングの推奨事項に期待するものとは異なることを理解しています。しかし、プログラミングの間違った方法はありませんので、その哲学に同意できない場合は、質問を嫌いにならないでください。BOOST_PPライブラリが存在するのには理由があり、この質問も同じ精神です。しかし、それは不可能かもしれません。

4

3 に答える 3

2

コンパイラーの最適化に任せたほうがよいことをしようとしています。

int main (void) {
  int b = 5;
  int a = b * 2;

  return a; // return it so we use a and it's not optimized away
}

gcc -O3 -s tc

 .file "t.c"
 .text
 .p2align 4,,15
.globl main
 .type main, @function
main:
.LFB0:
 .cfi_startproc
 movl $10, %eax
 ret
 .cfi_endproc
.LFE0:
 .size main, .-main
 .ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)"
 .section .note.GNU-stack,"",@progbits

コンパイラを最適化すると最適化されます。

編集:コンパイラが「すべき」または「通常」そうすることを聞きたくないことを私は知っています。ただし、実行しようとしているのは、Cプリプロセッサで実行することを意図したものではありません。C言語とCプリプロセッサを設計した人々は、それが基本的なアトムである前処理トークンで動作するように設計しました。CPPは、多くの点で「ダム」です。これは悪いことではありませんが(実際、多くの場合、これが非常に便利です)、結局のところ、これはプリプロセッサです。ソースファイルは、解析される前に前処理されます。セマンティック分析が行われる前に、ソースファイルを前処理します。特定のソースファイルの有効性がチェックされる前に、ソースファイルを前処理します。これがパーサーとセマンティックアナライザーが処理する必要がある、または通常実行するものであると聞きたくないことを理解しています。しかし、これが状況の現実です。信じられないほど小さいコードを設計したい場合は、プリプロセッサ構造を作成して作業を行うのではなく、コンパイラに依存して作業を行う必要があります。このように考えてください。コンパイラに何千時間もの作業が費やされたので、その作業をできるだけ多く再利用してみてください。

于 2010-10-08T19:32:01.700 に答える
1

ただし、直接的なアプローチではありません。

struct operation {
    template<int N>
    struct compile {
        static const int value = N;
    };
    static int runtime(int N) { return N; }
};

operation::compile<5>::value;
operation::runtime(5);

あるいは

operation<5>();
operation(5);
于 2010-10-07T18:20:12.463 に答える
1

2つのレベル(プリプロセッサと変数の評価)が混在する可能性は実際にはありません。あなたの質問から私が理解していることからb、象徴的な定数であるべきですか?

伝統的なものを使うべきだと思います

#define TWICE(n) ((n) * 2)

ただし、式を使用して変数を初期化する代わりに、コンパイル時定数を使用して変数を初期化する必要があります。コンパイル時に評価を強制し、Cにシンボリック定数を持たせるために私が目にするのは、整数列挙定数だけです。これらは型を持つように定義さintれ、コンパイル時に評価されます。

enum { bInit = 5 };
int b = bInit;
enum { aInit = TWICE(bInit) };
int a = aInit; 

constそして、一般的に、あなたは(あなたのように)あまり倹約するべきではなくb、生成されたアセンブラを。でチェックしてください-S

于 2010-10-07T19:52:30.857 に答える