2

私の C コードには、NULL ポインターであってはならないパラメーターとして、さまざまな構造体へのポインターを持つ多くの関数が含まれています。コードを読みやすくするために、次のコードを置き換えることにしました。

if(arg1==NULL || arg2==NULL || arg3==NULL...) {
    return SOME_ERROR;
}

そのマクロで:

NULL_CHECK(arg1,arg2,...)

引数の数が不明で、異なる構造体を指すことができる場合、どのように記述すればよいですか? (私はC99で働いています)

4

3 に答える 3

7

IMO で最も維持しやすい解決策は、「賢く」しようとするのではなく、複数の個別の呼び出しを作成することです。

たとえば、Win32 プログラマーは、デバッグ時にアサーションを実行する VERIFY マクロを使用します (このマクロは、アサーションがリリース コードから取り除かれることを保証します)。次のように始まる関数を見るのは珍しいことではありません:

int foo(void* arg1, char* str, int n)
{
    VERIFY( arg1 != NULL );
    VERIFY( str != NULL );
    VERIFY( n > 0 );

明らかに、これらの 3 行を 1 行に簡単にまとめることができますが、そうしないとマクロが最適に機能します。それらを別々の行に入れると、失敗したアサーションは 3 つの条件のどれが満たされていないかを示しますが、それらすべてを同じステートメントに入れると、何かが失敗したことがわかり、残りを理解する必要があります。

于 2012-04-08T21:09:37.293 に答える
1

マクロを使用する場合は、単一の引数を取るマクロを使用することをお勧めします。

#define NULL_CHECK(val)  if (val == NULL) return SOME_ERROR;

次に、次のように記述できます。

NULL_CHECK(s1.member1);
NULL_CHECK(p2->member2);

利点の 1 つは、このような最初の無効なメンバーを特定するために、エラー レポートまたはログを正確に組み込むことができることです。複合条件が 1 つの場合、そのうちの少なくとも 1 つが無効であることがわかりますが、正確にどれが無効であるかはわかりません。

可変数の引数を処理する必要がある場合は、 を調査する必要がありますBoost::Preprocessor。これは、C と C++ で機能します。

于 2012-04-08T23:31:17.550 に答える
0

マクロ内にステートメントを隠すのは良い考えだとは思いませんがreturn、そのようなマクロは次のように書くことができます。

#define NULL_CHECK(...)                                 \
  do {                                                  \
    void *_p[] = { __VA_ARGS__ };                       \
    int _i;                                             \
    for (_i = 0; _i < sizeof(_p)/sizeof(*_p); _i++) {   \
      if (_p[_i] == NULL) {                             \
        return SOME_ERROR;                              \
      }                                                 \
    }                                                   \
  } while(0)

基本的に、varargsを配列に展開し、インデックスをループします。

于 2012-04-08T23:50:34.427 に答える