2009-07-24 16 views
2

Cの関数の動作をプリプロセッサの助けを借りて変更しようとしています。オプションのパラメータのための基本的なパターンは簡単で、また...コンパイル時の関数デコレータ(ラッパー)

をオフに設定したりすることができ、オプションのパラメータを追加します。

#ifdef OPT_PARAM 
    #define my_func(a, b, opt) _my_func(a, b, opt) 
#else 
    #define my_func(a, b, opt) _my_func(a, b) 
#endif 

/*the rest of the code always calls "my_func" with all the params 
and not the underscored version...*/ 

#ifdef OPT_PARAM 
void _my_func(int a, int b, int opt) 
#else 
void _my_func(int a, int b) 
#endif 
{ 
    /*... more #ifdefs surrounding opt uses */ 
} 

条件付きで機能をラップするためのパターンが似ていますが、問題がありますアンダースコアが加算され始めます(入れ子の各レベルごとに1つの余分なものがあります。異なる関数にすることも、ラップされていない場合には次のレベルの#defineにすることもできます)。

ここでコードの複雑さをどのように減らすかについてのアイデアはありますか?

P.S.私はPythonを使いたいと思っています...しかし、これはドライバのためのものです:-(

+0

あなたは確かにvariadic関数を望んでいませんか? http://en.wikipedia.org/wiki/Varargs#Variadic_functions_in_C.2C_Objective-C.2C_C.2B.2B.2C_and_D – Inshallah

+0

かなり私はそれらを望んでいないことを確かめてください!^_ ^私はすでにそれらを使用しており、静的型検査の喪失に非常に懸念しています。 – fortran

+1

おそらく私は何かが不足していますが、これは私にはうまく見えます。余分な複雑さはどこにありますか?入れ子になるのは何ですか? –

答えて

0

である私は、一様に、余分なパラメータを処理し、より説明的な名前で無名のアンダースコアを変更し、新たなデコレータを追加しました。

これは、ランタイムオーバーヘッドなしでコンパイル時に動作をプラグインまたはプラグ解除できるようになりました。

2

デフォルトの引数やCで利用できないものを使いたいかのようです。これは悪い考えです。引数を指定しない場合、あなただけのNULLまたは-1(標準)を通過し、よりCのファッション、で物事を処理できません。

​​
+0

デバッグ用です。私は最終ビルドで余分なパラメータを取り除く必要があります...とにかく、それはラッパーのネストの問題を解決しません:-s – fortran

+0

彼はオプションのパラメータを使用しようとしていると思います。設定されている場合は、my_func(a、b、opt)を呼び出すか、my_func(a、b)を呼び出します。 – Gert

+0

@fortran:どうしてネストする必要がありますか?あなたは、各機能の2つ以上のバージョン(デバッグと最終)を持っていますか? – Christoph

1

を私は、これはあなたが望むものに近いかもしれないと思うが、私は理解していません。考えられるのは、任意の数の引数を持つc関数に型チェックされ、コンパイル時に排除できるということです。

標準を引用することで、識別子のスコアあなたは予約された識別子に遭遇するかもしれません。しかし、これの可能性は私には分かりません。

ISO/IEC 9899:1999(E)7.1.3

- アンダースコアと大文字 文字または他のアンダースコアのいずれかで始まるすべての識別子は常に使用するために予約 です。

このソリューションにはGCCが必要です。 GCCのバージョンは弱いシンボルもサポートしなければなりません。コンパイラが弱い記号を使用して正しい関数定義を探すことを可能にすることです。さらに、機能の内容は、つまり、コンパイラが死んだ枝を剪定すべきであるという知識を使用することによって単純化されています

if (0) { ... } 

コンパイル時にさらなる分析なし(GCC 4.xのは、確かにこれを行います)。存在しないオプションのパラメータをcプリプロセッサ(cpp)シンボルとして定義することで、関数本体にcpp条件を持たせることを避けることができます(必要な場合)。以下のf_opt0に対して、opt1とopt2がどのように定義されているかを見てください。

#include <assert.h> 
#include <stdio.h> 

extern void f_opt0(int a, int b) __attribute__((weak)); 
extern void f_opt1(int a, int b, int opt1) __attribute__((weak)); 
extern void f_opt2(int a, int b, int opt1, int opt2) __attribute__((weak)); 

#ifdef OPT0 
void f_opt0(int a, int b) { 
#define opt1 0 
#define opt2 0 
#endif 
#ifdef OPT1 
void f_opt1(int a, int b, int opt1) { 
#define opt2 0 
#endif 
#ifdef OPT2 
void f_opt2(int a, int b, int opt1, int opt2) { 
#endif 
    if (opt1) printf("opt1=%d\n", opt1); 
    if (opt2) printf("opt2=%d\n", opt2); 
    printf("a+b=%d\n", a+b); 
    #undef opt1 
    #undef opt2 
} 

#define f(a, b, o1, o2) \ 
    if (f_opt2) f_opt2(a, b, o1, o2); \ 
    else if (f_opt1) f_opt1(a, b, o1); \ 
    else if (f_opt0) f_opt0(a, b); \ 
    else { assert(0 && "no f() defined!"); } 

int main(void) { 
    f(1, 2, 1, 1); 
    return 0; 
} 

私のテストは非常に限られていた、と私はそれが問題になりやすいようだと理解する面倒であるC.で、このように良いデザインを提唱していません。しかし、私はあなたの目標に応えてくれることを願っています

2

C++コンパイラを使用できますか? ちょうど関数のオーバーロードを(C++の機能の)使用することができます。

別のオプションは、最後に

#ifdef OPT_PARAM 
# define OPT(X) , X 
#else 
# define OPT(X) 
#endif 

int my_func(int a, int b OPT(int opt)) { 
#ifndef OPT_PARAM 
    int opt = default_value; 
#endif 
    ... // Rest of code 
} 


... 
// calling it 
my_func(2, 4 OPT(42)); 
関連する問題