C言語でforeachを書いてみた

Boost.Foreachを参考にした。
Boost.Foreachと違ってbeginとendはループの度に評価されるので、副作用を入れこまないように注意

#define FOREACH_C89( var, begin, end ) \
    for( var = (begin); var<(end); var++ )

#define FOREACH_C99( var, begin, end ) \
    for( size_t _foreach_i=0,_continue=1; _continue && (((begin) +_foreach_i)< (end)); _continue ? _foreach_i++ : 0 ) \
        for(int _foreach_j = (_continue=0); !_foreach_j; _foreach_j=1 ) \
            for( var = (begin) + _foreach_i; !_continue; _continue=1 )

#define FOREACH( var, begin, end ) FOREACH_C99( var, begin, end )

C++と違ってCではifを使った局所変数宣言ができないので、ダミーのfor文で代用している。

C89とC99の違いは、for文中で変数宣言ができるか否か

void test_foreach{
    // C89版は値を受ける変数を事前に宣言しておく必要がある。
    int i;
    FOREACH_C89( i, 0, 12 ){ printf("c89:\d\n", i ); }

    // C99版はその必要なし
    FOREACH_C99( int j, 0, 12 ){ printf("c99:\d\n", j ); }
}

配列(ポインタ)の繰り返しもできる

#define SIZEOF_ARRAY(ary) (sizeof(ary)/sizeof(ary[0]))
#define ARRAY_END(ary) (ary + (SIZEOF_ARRAY(ary)))

void test_foreach(){
    short s_array[] = {1,2,3,4,5,6,7,8};
    FOREACH( short *n, s_array, ARRAY_END(s_array) ){
        printf("val: %d\n",*n );
    }
}

おまけ

#define FOREACH_ARRAY( var, ary ) FOREACH( var, ary, ARRAY_END(ary) )
#define TIMES( count, var ) FOREACH(var, 0, count )

#define RANGE(type) struct { type begin; type end; }
#define FOREACH_RANGE( var, range ) FOREACH( var, range.begin, range.end )

void test_foreach(){
    int array[] = { 2,4,5,6,12,7 };
    FOREACH_ARRAY( int *n, array ){
        printf( "%d\n", *n );
    }

    TIMES( 5, int n ){ printf("times:%d\n", n ); }

    RANGE(int) rng = {0,12};
    FOREACH_RANGE(int n, rng ){ printf("range :%d\n", n ); }