2017年5月26日金曜日

sscanfのバグ?

 安易に「バグ」というと、「仕様かもしれないだろ!製作者に問い合わせしたのか!?」と突っ込まれたりするらしいので、「謎の挙動」あたりにしておこうかと思いますが。

 char str[] = "hoge 1 2 3"という文字列が有った時に、int i, x, y; uint8_t z;という変数があり、i = sscanf(str + 5, "%d %d %hhu", &x, &y, &z);とした場合、i, x, y, zがそれぞれ3, 0, 2, 3となるとてもふしぎな現象がarm-none-eabi-gccで発生しました。詳細なバージョンは覚えてませんが、4系と5系で発生しています。

 ちなみに、int i, x, y, z;で、フォーマットが"%d %d %d"の場合は問題なく3, 1, 2, 3という結果になります。
 さらに蛇足ですが、一旦"%d %d %d"で変換した場合は、uint8_tを含む"%d %d %hhu"でも問題なく変換できるようです。
 sscanfの実装は見たことがありませんが、なんとなく静的変数の初期値の問題っぽい気がします。一番有り得そうなのは僕が書き換えたリンカスクリプトかなーという気もしますが。

 まぁ、一番手っ取り早い方法は全部intで受け取ることかな、と思います。いちいちビット幅とか気にしないでいいですし、どうせスタックから取ってすぐ開放するんですからメモリ使用量とかも気にしないで(ゲフンゲフン


 どうでもいいですが、「sscanf バグ」でググると、scanfはバッファオーバーランを防げないから使うな、みたいな泥仕合が展開されているようです。
 個人的にはwikipediaに書いてある方法で変数に読み込みつつ、あとでsscanfでパース、というのが楽でいいかなと思います。そんなこと言い始めるとセキュリティ云々とか悪意のあるものが云々とかいろいろ噴出するんでしょうけども。。。

 printfやscanfのフォーマットは、表示するフォーマットと、使用する変数を別の部分で管理できるので、楽だと思っています。C#のConsole.Writeのような方法では変数とフォーマットが複雑に入り混じって面倒です。でもprintfだとどの変数がどこに入って、というのを考える必要があるし、後続の言語でprintfやscanfのようなフォーマットがマイナーになってるからには万人から支持されている方法ではないんだろうなぁとも思います。


 ということで、「よくわからないなぞのきょどう」の話でした(ばぐじゃないよっ!

0 件のコメント:

コメントを投稿