#この記事について
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のアドレス値