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

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

2007/4/4(Wed)

[NetBSD] vfprintf(3)

塩崎さんとこより。

以前のことですがFreeBSDのvfprintf(3)に比べてNetBSDの実装が異常に遅かったんで
gprof(1)で統計取ったんですけど、やっぱりmbrtowc(3)はボトルネックになってましたね。
(intmax_t使いまくりなのが最大のボトルネックで、それ直すだけでだいぶ改善したんですが)

先日mbrtowc(3)呼ばないと困るなぁとは書いたんですが、以前のvfprintf(3)の実装では

という方法だったので、ja_JP.ISO2022-JP localeの場合
これとか これがあって、どのみち問題ありだったのを思い出しました。

というわけで

  1. singlebyte locale用
  2. stateless multibyte locale〃
  3. stateful multibyte locale〃

の3つくらいを用意するべきなんでしょうかね。
今の実装でも頑張ればMB_CUR_MAXとmbrtowc(NULL, NULL, 0, ps)の戻り値のチェックで
ある程度は最適化できるかもしれないですけど。

[C言語] 続 scanf(3)

昨日の続き。

@ scanf + %s + field width

これは大丈夫。

#include <stdio.h>

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

	scanf("%3s%n", buf, &n);
	printf("%d:%s\n", n, buf);
	return 0;
}

stdinから(EOFに達しない限り)width=3byte読み込まれ、bufに書き込まれます。
bufは必ず'\0'で終端されますので、width + 1だけ確保するように。
ただし、この'\0'はstdinから読み込まれたものではないので
%n(現在までstdinから読み込んだbyte数を返す)にセットされる値はあくまで3です。

@ wscanf + %ls + field width

これも大丈夫。

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

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

	setlocale(LC_CTYPE, "");
	wscanf(L"%3ls%n", buf, &n);
	wprintf(L"%d:%ls\n", n, buf);
	return 0;
}

stdinからはfgetwc(3)相当を用いて(WEOFが返されない限り)
最大width=3ワイド文字分読み込まれ、bufに書き込まれます。
bufは必ずL'\0'で終端されますので、width + 1だけ確保するように。
ただし、このL'\0'はstdinから読み込まれたものではないので
%n(現在までstdinから読み込んだワイド文字数を返す)にセットされる値はあくまで3です。

@ scanf + %ls + field width

これも scanf + %lc + field widthと同様に、実装によって差があります。

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

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

	setlocale(LC_CTYPE, "");
	scanf("%3ls%n", buf, &n);
	printf("%d:%ls\n", n, buf);
	return 0;
}

以上のコードを実行した結果

どちらの仕様が正しいかといわれると、私はFreeBSDとNetBSDだと思います。

@ wscanf + %s + field width

ウンザリしてきましたが orz
wscanf + %c + field widthと同様、実装によって差があります。 以上のコードを実行した結果

どちらの仕様が正しいかといわれると、これはglibc2とVisualC/C++が正しいと思います。
不幸なことにbufに必要なサイズが実装によって異なるので、これもオーバーランの可能性があり危険です。

@ 結論

昨日とおなじで OpenBSD
じゃなくて scanf + %ls、wscanf + %s をfield width付きで使うのは、こんな状況では避けるのが無難でしょう。

@ つか

Google codesearchで調べる限り

なんで心配するだけ無駄な気がしてきたwwwwww
古典的な w?scanf + %(l?s|S)みたいな危険なコードの方の心配の方が先かも。


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