C99のVLAは関数の本体が空でもコードが書ける
https://lemon.rip/w/c99-vla-tricks/
C99のVLAはだいぶ狂っている。
C99のVLA(Varriable Array Length)は実行時にサイズが決定される配列だ。VLAは関数の引数にも使える。
void f( int n, int a[n] )
{
int b[n] ;
// sizeof(int *)
int A = sizeof(a) ;
// sizeof(int) * n
int B = sizeof
}
配列型の引数は通常のルールにしたがってポインター型になるのだが、VLAの配列内の要素数については、実行時に計算される。ところで、VLAの配列の要素数には任意の式を書ける。
void f( int a, int b, int c[a+b] ) {}
void g( int x, int b[abs(x)] ) {}
void h( int a[getchar()] ) { }
こうなると次にどういうコードが書かれるかはお察しの通りだ。
int main( int argc, char * argv[ printf("Hello,World")] ) { }
ところでC言語にはカンマ演算子がある。
int main( int argc, char * argv[(
printf("Enter a character:"),
getchar(),
printf("bye"),
1
)]){}
条件分岐は条件式で実現できる。
void f(int n) {
if (n < 0)
printf("negative!");
else if (n > 0)
printf("positive!");
else
printf("zero!");
}
というコードは、
void f(int n, char _[( (n < 0) ? printf("negative!") : (n > 0) ? printf("positive!") : printf("zero!") , 1 )]) {}
と書ける。
戻り値を返すことはポインター型の引数で表現できる。
void fswapf(float *a, float *b) {
float tmp = *a;
*a = *b;
*b = tmp;
}
配列の要素数のなかに書けるのは式なのでfor文やwhile文を書くことはできない。しかし関数の再帰呼出しはできるのでループも表現できる。
/* the forward declaration is necessary */
static void sum_aux(float *out, float *v, size_t n, char *);
static void sum_aux(float *out, float *v, size_t n, char _[(
(n > 0) ? (
*out += *v,
sum_aux(out, v + 1, n - 1, ""),
1
) : 1
)]) {}
void sum(float *out, float *v, size_t n, char _[(
*out = 0.0f,
sum_aux(out, v, n, ""),
1
)]) {}
VLAは狂っている。