isalpha() はどんな値を返すのか?


isalpha() はどんな値を返すのか?

Twitter の TL 上に isalpha() は今も昔も zero か nonzero だ、というのが流れていた。

ちょっと古いが C99 には、isalpha() を含む関数群の記述が 7.4 にあり、基本的な動作は、7.4.1 Character classification functions に、以下のように書いてある。

The functions in this subclause return nonzero (true) if and only if the value of the argument c conforms to that in the description of the function.

true ってなんだよ、が書いてあるのだから、当然、false ってなんだよ、も書いてあるのだが、それは自分で探してください。zero ですが。

isalpha() は、以下のような記述になっている。

The isalpha function tests for any character for which isupper or islower is true, or any character that is one of a locale-specific set of alphabetic characters for which none of iscntrl, isdigit, ispunct, or isspace is true. In the "C" locale, isalpha returns true only for the characters for which isupper or islower is true.

isupper() とは、islower() とは、character set とは、と辿っていく必要があるのだが、平たく書けば、C ロケールで引数 c が大文字か小文字なら true (nonzero) を返す、ということになる。

ここまでが C99 での記述。

じゃあ、POSIX ではどうなっているのか。

IEEE Std 1003.1-2008 / Single UNIX Specification Version 4 の isalpha() の RETURN VALUE には、以下のように書いてある。

The isalpha() and isalpha_l() functions shall return non-zero if c is an alphabetic character; otherwise, they shall return 0.

こっちのが記述としてはぐっと分かりやすい。

歴史の話がしたいわけじゃないので、昔はどうだったかまでは遡ることまではしないけれど、少なくとも今は non-zero/zero としか書かれていない、というのは間違いない。

で、実際、どんな値が返ってくるわけ?

non-zero ってどんな値?

non-zero としか書いてないのだから、少なくとも 1 とは限らない。2 も -1 も non-zero なのだから。

やってみるしかないね。

とりあえず小文字の場合はどうなるのかを調べる C のコードを Gist にあげておいた。

Which value is returned by isalpha() ?

これを NetBSD 6.1.4 と Ubuntu 14.04 LTS で実行してみた結果、NetBSD 6.1.4 では 2 が返り、Ubuntu 14.04 LTS では 1024 が返ってきた。

この時点でだいぶ疲れてきたので、NetBSD の方だけを調べる。

isalpha()ctype.h にあるはずなので、/usr/include/ctype.h を見てみる。

関数の定義だけだ...

さっきの ctype.h の最後に何やら、それらしい別のヘッダーファイルがあるので、そっちを見てみる。

sys/ctype_inline.h

#define isalpha(c)
((int)((_ctype_ + 1)[(c)] & (_CTYPE_U|_CTYPE_L)))

※改行いれて見栄えを調整してあるけど、実際は一行です。

sys/ctype_bits.h

#define _CTYPE_U 0x01
#define _CTYPE_L 0x02

あと、分かっていない _ctype_ は、/usr/src/lib/libc/gen/ctype_.c にある。

const unsigned char *_ctype_ = &_C_ctype_[0];

_C_ctype_ は同じファイルに定義してある。

ということで、NetBSD 6.1.4 では、

こういう構造になっているので、小文字を isalpha() に食わせると、_CTYPE_L つまり 2 (== 0x02) が返ってくる、というわけです。

補足事項

同じ NetBSD でも、-current では 2 は返ってきません。このあたりががっつり変更されているからです。なんでかは踏み込まない方がいいと思います。

Linux ? glibc ? も、ビットマップっぽい値 (1024 == 0x400) が返ってきてるから、たぶん似たようなことしてるんでしょう。

OS X 10.9 Marvericks だと 1 が返ってきてました。


戻る