LoginSignup
26
25

More than 3 years have passed since last update.

C言語でよく定義するマクロまとめ

Posted at

この記事について

C言語でよく定義するマクロを記載します。

真偽値

C99で_Bool型が定義されましたが、C99が使えない場合や、何らかの理由で真偽値を定義するときは、FALSEを0、TRUEを非0で定義します。

#define FALSE (0)
#define TRUE  (!FALSE)

固定配列の長さを取得

よく使います。配列長を個別にマクロ化するより柔軟に対応できます。

#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
使用例
int a[10];
int i;
for(i=0; i<ARRAY_LENGTH(a); i++){
    a[i] = i;
}

固定配列の境界アドレス値の取得

#define ARRAY_BEGIN(array) (array)
#define ARRAY_END(array)   (array + ARRAY_LENGTH(array))

配列インデックスが範囲内であることのチェック

#define IS_VAILD_RANGE(array, i)  ( (ARRAY_BEGIN(array) <= (array) + (i)) && ((array)+(i) < ARRAY_END(array)) )

ポインタが非NULLであることのチェック

非NULLチェックはよく使うのでマクロ化しておくと便利です。

#define IS_NOT_NULL(ptr) ( (ptr) != NULL )

組み込みAssertマクロのリネーム

組み込みマクロはそのままコールせず、リネームして呼び出すことで、異なるアサーション関数の呼び出しに変更するなど、柔軟に対応できるようになります。

#define ASSERT(cond)   assert( (cond) )

DbC (Design by Contract)用のマクロ

契約プログラミング(DbC:Design by Contract)を実施するためのマクロです。assertを直接コールしても実現できますが、Assertマクロのリネームと同様、事前条件、事後条件、不変条件を別々にマクロ化しておくことで、機能変更や有効/無効などを柔軟に対応できるようになります。

/* 事前条件 */
#define REQUIRE(cond)       ASSERT(cond)

/* 事後条件 */
#define ENSURE(cond)        ASSERT(cond)

/* 不変条件 */
#define INVARIANT(objname)  objname##_invariant(void)
使用例
void function(int* array, int len){
    REQUIRE(array != NULL);
    REQUIRE(len > 8);

    // ・・・処理
}

静的アサート

コンパイル時に静的にチェックしておきたいアサート条件を定義します。アサート条件に引っかかった場合、コンパイルエラーとなります。

#define STATIC_ASSERT(COND) { char static_assertion_failed[(COND)?1:-1]; }
使用例
STATIC_ASSERT( sizeof(int) == 4 );

失敗すると以下のようなコンパイルエラーがでます。アサート条件に引っかかると「長さが負数の配列を定義しようとする」ことを利用してコンパイルエラーを引き起こしているため、そのようなエラーがでます。

XXXX.c:行数: error: 'static_assertion_failed' declared as an array with a negative size
    STATIC_ASSERT(sizeof(int) == 3);

注:この定義の場合、「unused variable」の警告が出る場合があるため、それが許容できる場合のみの使用となります。

構造体のメンバー変数の先頭からのアドレスオフセットを取得する

マニアックですが、構造体メンバの先頭からのアドレスオフセットを取得します。Linux kernel.hに同様のものが定義されています。

#define offsetof(type, member) ((size_t) &((type*)0)->member)
使用例
struct Sample{
    int a;
    float b;
    double c;
};

int main(void){
    printf("%d\n", offsetof(struct Sample, a) );  // 0
    printf("%d\n", offsetof(struct Sample, b) );  // 4
    printf("%d\n", offsetof(struct Sample, c) );  // 8
}

構造体メンバへのポインタから、そのメンバを含む親元の構造体変数のポインタを取得

#define container_of(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type,member)))
使用例
struct Sample s;
float* p = &s.b;
printf( "%p\n", container_of(p, struct Sample, b) ); // &sのアドレス値
26
25
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
25