Tuesday 22 November 2011

C のマクロ使いまくりで幸せになる奴なんていない

あまり大きな声では言えないが、プロシンの原稿を11月中に出したことはないらしい… 今年の〆切は11/18だったのに。

今年も4年次がプロシンに出してくれるのはうれしいんですが、締め切りすぎてから「プログラムが動きません」は、やめようよ〜 と言いながら、コンパイラのデバッグ。

Lion になって gcc が llvm になっても、自分で作ったコンパイラにはさほど影響はないけど、ちゃんと動かなくなってる。gcc は llvm では作れないので gcc で作るしかないらしいです。

今回の問題はマクロ。C のマクロは最低だから、なるべく使わないようにしようって話じゃなかったの? Linux kernel も Lion の stdio.h も、

## マクロシンボルの結合
# マクロシンボルの文字列化

の使いまくり。そこで気が付いたんですが、マクロシンボルの結合って、マクロをeval前に結合されるのね。それは変だろと思うけど、

結合したシンボルを、さらにマクロとして使う

ということらしい。結合する前のシンボルが#define されてなければ問題にならないので普通は気にする必要はないんだけど、stdio.h でやられちゃうとなおすしかない。 http://ruiu.blogspot.com/2010/07/c_25.html によると、やっぱり ## だけ先読みして特別扱いするらしい。# も同じらしい。

 *  *  *  *

Lion だと、

FILE *fopen(const char * __restrict, const char * __restrict) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_3_2, __DARWIN_EXTSN(fopen));

ってな感じになっていて、

#define __DARWIN_ALIAS_STARTING(_mac, _iphone, x) __DARWIN_ALIAS_STARTING_MAC_##_mac(x)

で結合して、

__DARWIN_ALIAS_STARTING_MAC___MAC_10_6( __asm("_" "fopen" ))

ってな形で呼ばれるようです。

#define __MAC_10_6 1060

なんだけど、

__DARWIN_ALIAS_STARTING_MAC_1060( __asm("_" "fopen" ))

とか

__DARWIN_ALIAS_STARTING_MAC___MAC_10_6( __asm("_" x ))

にはならないところが肝だね。_mac は一段だけ展開、x は先まで展開と。まぁ、その方が、こういう使い方ができて便利だってことなんでしょうけど。せめて、

#define __MAC_10_6 1060

これは、やめて欲しかった。

 *  *  *  *

Linux kernel でも、

SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)

とかいうマクロで kernel 内の system call を定義するようになった。なので、entry.S の sys_write を grep しても見つからない。いや、もちろん、fs/read_write.c にあるのは常識だよね? でも、こんなマクロで誰が幸せになるの?

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

で、variadig なマクロを使って、

#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
#define SYSCALL_DEFINE(name) static inline long SYSC_##name
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \
{ \
__SC_TEST##x(__VA_ARGS__); \
return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))
#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
#define SYSCALL_DEFINE(name) asmlinkage long sys_##name
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

こうだよ。君達は何がしたいんですか。こんなもの使わずに config で生成しろと思う。そうすれば生成したものを読めるらから。gcc -E するのだって結構大変なのに。これ以上可読性落してどうするの?

No comments: