arduino用にsscanf関数のサブセットを作成

d161118a1C/C++のプログラムで簡単な文字列解釈が必要になった時、sscanf()で処理しているのだが、esp8266 arduino環境だと使えない。コンパイルは通るがリンク時にエラーとなる。仕方がないので strtol()関数などで凌いでいたのだが、浮動小数点の解釈をする必要があり、StringのtoFloatの説明を見ているうち、段々腹が立ってきて、sscanf()のサブセットを作ることを思いついた。

toFloat()で許せないのは、数字として解釈できなかった場合0を返すだけで、元の文字列を見ないと数字だったのかどうかわからないこと。解釈できたかどうかをbool値で返し、値は引数に変数のポインタを渡して返すべきだと思う。

sscanfで日ごろ使うのは%d,%x,%f程度。そういう仕様で作ってみたら70行ぐらいだった。こんなことなら、もっと早く作っておけばよかった。githubで公開したので、間違いなどあれば指摘してもらうと嬉しいかもしれない。

avrlibcにはsscanfがあるようなのでArduinoでもAVRだと使えるのかもしれない。

toFloat()の文句を書いているうち、sscanfでも “123!”のように数字の後に余分な文字がある場合を上手く識別できないのが気になって来た。フォーマット文字列で”%d%c”とかやって、後続の空白文字以外の文字がないことを判定してやれば良いのかもしれないが、余分な変数と引数が必要になる。正規表現みたいに文字列の最後にマッチする奴があれば綺麗に判定できるのにと思いnscanfに、その機能もつけてみた。%+何かの文字でマッチさせたいところだが、nscanfにはformat/scanf attributeを付けているのでgccに警告される。空白文字はフォーマット文字列中で無視されるので、フォームフィード(\f)でマッチさせることにした。以下のように使用できる。

 int i;
 if(nscanf(buf,"%d\f",&i) != 2)
   fprintf(stderr,"Bad integer strng:%s\n",buf);

今後、使っていって、気が向いたら機能拡張しよう。

Comment

  1. 木村真也 より:

    static int n_isspace(char c)
    {
    return c == ‘ ‘ || c == ‘t’ || c == ‘\n’ || c == ‘\r’;
    }

    c == ‘\t’ では?

    ※今年からコンパイラの講義を担当することになり,演習に最適なテーマになりそうです.

  2. nari より:

    ご指摘ありがとうございます。そのとおりです。修正しました。

    お恥ずかしいです。何ですかね、プログラム見えてないんですかね。

    でも、段々バグが減っていく感じが好きです。

Leave a Reply

メールアドレスが公開されることはありません。