The Man Who Fell From The Wrong Side Of The Sky:2007年4月3日分

[最新版] [一覧] [前月] [今月] [翌月]

2007/4/3(Tue)

[C言語] scanf(3)

scanf/wscanfファミリーを使うときのちょっとした注意おば。

@ scanf + "%c" + field width

これは大丈夫。

#include <stdio.h>

int main(void)
{
	char buf[3];
	int n;

	scanf("%3c%n", &buf[0], &n);
	printf("%.*s", n, buf);

	return 0;
}
width = byte数(char)

の計算ですので、bufの長さはwidthと同じだけ用意すればOK。
stdinからは(EOFに達しない限り)最大width=3byte読み込まれ、bufに書き込まれます。

@ wscanf + "%lc" + field width

これも大丈夫。

#include <locale.h>
#include <stdio.h>
#include <wchar.h>

int main(void)
{
	wchar_t buf[3];
	int n;

	setlocale(LC_CTYPE, "ja_JP.eucJP");
	wscanf(L"%3lc%n", &buf[0], &n);
	wprintf(L"%.*ls\n", n, buf);
	return 0;
}
width == ワイド文字数(wchar_t)

の計算で、 bufも同じ長さだけ確保。
stdinからはfgetwc(3)相当を用いて(WEOFが返されない限り)
最大width=3ワイド文字分読み込まれ、bufに書き込まれます。

@ scanf + "%lc" + field width

こいつは曲者です、実装により差があります。

@ wscanf + "%c" + field width

こっちも困ったことに実装により差があります。
詳しくは 昨日のメモ以前のメモを参照してください。
どちらが正しいかといわれると、 SUSv3読む限りでは、今度は逆にglibc2とVisualC++の方が正しい実装のように思えます。
不幸なことに実装によって必要とされるbufの長さがまちまちなので
FreeBSDで書いたコードがLinuxではオーバーランなんて事態が起きる可能性があります。

@ 結論

C99拡張を取り込んでないOpenBSD最強
以上の通り実装によっててんでバラバラなんで
scanf + %lc、wscanf + %c をfield width付きで使うのは避けた方がいい鴨。
そもそもどちらもbufに何byte、何文字書かれたか判らないという欠点もあることだし。
その他のscanf(3)を使うときに注意する点は C FAQでも読んで頂戴。


[ホームへ] [ページトップへ]