1

純粋なC(C ++からのもの)を学ぶために、構造体とマクロを使用して単純な数学ライブラリを作成することにしました。

これまでのところ、私はこれをテストマクロとして持っています:

#define MulVec2(dest,src) ((dest.x) = (dest.x) * (src.x); (dest.y) = (dest.y) * (src.y); return dest;)

typedef struct vec2f_s
{
    float x, y;
}
vec2f_t;

私の呼び出しコードには、次のようなものがあります。

int main(void)
{

    vec2f_t v, w;

    v.x = 5.0f;
    v.y = 2.0f;

    w.x = 3.0f;
    w.y = 3.0f;

    v = MulVec2(v, w);

    printf( "x => %f; y => %f \n", v.x, v.y );

    return 0;
}

私の質問は次のとおりです。

1)オブジェクトのポインタ/アドレスをマクロに渡すために別のマクロを作成する必要がありますか?もしそうなら、どのように?たとえば、MulVec2(dest,src)マクロは渡されたオブジェクトが動的に割り当てられていないことを前提としていることに注意してくださいが、それもサポートしたいと思います。

2)コードをコンパイルすると、次のエラーが発生します。

../main.c: In function 'main':
../main.c:15:9: error: expected ')' before ';' token
../main.c:15:7: error: incompatible types when assigning to type 'vec2f_t' from type 'float'

これを修正するにはどうすればよいですか?

編集

このためにマクロだけを使用する予定はないことを明確にする必要がありますが、マクロを作成する理由は、ベクトルのdoubleとfloatのバリエーションに対して個別の関数を作成する必要がないためです。DRY(繰り返さないでください)の原則に従って、可能な限り再利用できるようにしたいと思います。

4

5 に答える 5

2

他の人が指摘しているように、マクロは関数ではなく、これは関数のユースケースになります。マクロは、Mul2Vec(...)をマクロで記述したものにテキストで展開するだけですがreturn、式から抜け出すことができないため、コンパイラーには意味がありません。

CでC++テンプレートの効果を実現したい場合は、戦略を再検討してください。おそらく、floatまたはのいずれかを選択doubleして、それに固執するだけです。ただし、コードを重複させずにジェネリックスを実行する必要がある場合は、次のように関数定義マクロを定義できます。

/* vec-impl.h */

#define PASTE(a, b) a ## b
#define NAME(prefix, type) PASTE(prefix, type)

#define VEC_T NAME(vec_, T)

typedef struct {
  T x;
  T y;
} VEC_T;

void NAME(MulVec2_, VEC_T)(VEC_T *dest, VEC_T *src) {
 dest->x = dest->x * src->x;
 dest->y = dest->y * src->y; 
}

実際の関数を定義するコンパイル単位は次のようになります。

/* vec-double.c */

#define T double
#include "vec-impl.h"

/* vec-float.c */

#define T float    
#include "vec-impl.h"

この設定により、型推論や高度なメタプログラミング機能を使用せずに、貧乏人によるC++テンプレートの近似が可能になります。繰り返しになりますが、絶対に必要な場合を除いて、そのルートに進まないでください。その場合でも、それを実行するコードを最小限に抑えてください。これは慣用的なCコードではなく、有能なCプログラマーには受け入れられません。CはC ++よりもプリプロセッサのハッキングに対してオープンですが、これは十分に限界があります。

投稿したコードについて:マクロとは何かを理解するために、カーニハンやリッチーの「Cプログラミング言語」などのトピックを説明するCに関する優れた本を入手してください。マクロを調べるときは、次の点に注意してください。

  • 自分が何をしているのかを本当に理解していない限りreturn、マクロから抜け出すことはできません。とにかくそれを行う場合は、RETURNという単語をマクロ名の一部にします。同じことが、、、、などの他のフロー制御ステートメントにも当てはまりbreakます。あなたがそれを評価した後、そのコードを維持している人々。continuegoto

  • 慣例により、マクロは常にすべて大文字で綴られるため、MulVec2ではなくMUL_VEC2になります。これは、関数ではなくマクロを扱っていることを読者に警告します。

  • マクロ定義の括弧のポイントは、複合式が渡された場合でもマクロ展開が機能することです。したがって、それdestは括弧で囲まれている必要がありますdest.x。つまり、の代わりに(dest.x)、と書くでしょう(dest).x

  • コンパイラーへのスイッチを使用し-Eてプリプロセッサー出力を表示します。これにより、コンパイラーが何を認識しているかを確認し、何が起こっているかを把握できます。

于 2012-10-07T18:24:06.830 に答える
2

マクロは関数ではありません!

を呼び出すとMulVec2(v, w)、マクロが定義された値に置き換えられます。

前処理後、コードは次のようになります。

int main(void)
{

    vec2f_t v, w;

    v.x = 5.0f;
    v.y = 2.0f;

    w.x = 3.0f;
    w.y = 3.0f;

 v=MulVec2(dest,src) ((dest.x) = (dest.x) * (src.x); (dest.y) = (dest.y) * (src.y); 
    return dest;)


    printf( "x => %f; y => %f \n", v.x, v.y );

    return 0;
}

それがコンパイルエラーの理由です。の #define をMulVec2関数に置き換えるだけです。

于 2012-10-07T18:17:27.807 に答える
1

C99 コンパイラを使用している場合、このバージョンのマクロは、実行したいことを実行します。

  #define DOT2(a, b) ((vec2f_t){(a).x * (b).x, (a).y * (b).y})

慣例によりますが、特にここのケースのように引数を 2 回評価する場合、マクロには大文字の UGLY_NAME が必要です。私はマクロが大好きですが、このルールに従わないと失敗することを苦い経験から知っています。だから私はあなたもうまくいくMulVec2と置き換えましDOT2; MULVEC2た。

また、慣例により、マクロ パラメータは常に括弧で囲みます (例: ) (a).x。参照。通り。この規則の例外は、あなたが異常なことや間違ったことをしていることを読者に示します。しかしfabs((a))、おそらく不要です。

このマクロを使用すると、アドレスを取得することもできます (gcc でテスト済み):

   extern void foo(vec2f_t *);
   // ...
   foo(&DOT2(ying, yang));
于 2012-11-17T02:55:24.790 に答える
1

これは悪い設計です。引数を複数回評価するマクロは、引数として渡す式の副作用がコード全体を破壊する可能性があるため、非常にエラーが発生しやすくなります。C++ で使用inlineするのとほぼ同じ関数を使用します。

原則として、関数で実行できることにはマクロを使用しないでください。

そのような関数がある場合は、ポインターを介して引数を受け取る別の関数を作成し、名前を付けMulVec2pます。次に、型ジェネリック マクロと呼ばれる C11 の新機能を使用すると、C++ での関数のオーバーロードに似たことができます。

#define MULVEC2(X, Y)                \
(_Generic((X),                       \
  struct vec2f_s: MulVec2,           \
  struct vec2f_s*: MulVec2p)         \
   ((X), (Y)))

(これは最初の引数の型をテストするだけですが、画像が得られることを願っています。)

C11 はコンパイラによってまだ完全にはサポートされていませんが、たとえば clang には既に_Generic.

于 2012-10-07T18:21:29.990 に答える
0

2 番目の質問について - return desc を削除します。マクロから、このマクロを誰にも割り当てることはできません

于 2012-10-07T18:17:07.203 に答える