2012年11月4日日曜日

整数を文字列に変換する関数

整数を文字列に変換する関数を作ってみました

通常はsprintfとかでも十分ですが
今作ってる機材でprintf系の関数が使えない事態(ROMとかの問題ではない)が発生したので
後学のためにも作ってみました


微妙に高性能なitoa という感じです
簡単な動作確認はしましたが正常に動く保障はないです
多少高性能な事によるメリットよりも安定性が低いデメリットのほうが上回る程度です






int i2a(char *buf, int num, char mode, int len, char zeroF, char siM, char liF) {
    const char numStr[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    char *ptr = buf, *q, *p;
    char neF = 0;

    if (num < 0) { num *= -1; siM = 1; neF = 1; }

    do {
        *ptr++ = numStr[num % mode];
        num /= mode;
    } while(num);

    if (!liF) {
        if (siM && !zeroF)
        { *ptr ++ = neF ? '-' : '+'; siM = 0; }
        while (ptr - buf < len - siM)
        { *ptr++ = zeroF ? '0' : ' '; }
    }

    if ((siM && zeroF) || liF)
    { *ptr++ = neF ? '-' : '+'; }

    *ptr = '\0';

    p = ptr - 1;
    q = buf;

    while(p > q) {
        char c = *p;
        *p-- = *q;
        *q++ = c;
    }

    if (liF) {
        while (ptr - buf < len)
        { *ptr++ = ' '; }
        *ptr = '\0';
    }

    return(ptr - buf);
}


こんな感じになります

変数名とかは気にしないでださい


特徴
・符号付き32ビットの範囲を扱える
・(今まで僕が作ったitoaの中では)比較的メモリ消費量が少ない
・printfで使われるフラグの一部を使用することができる
・文字列長を指定できる
・基数を設定できる

という感じです

第1引数:変換後の文字列を格納するバッファ
第2引数:変換する整数
第3引数:基数(0~16まで 一部書き足しで常識的な範囲内ならおおよそ対応可能)
第4引数:最小文字列長
第5引数:フラグ'0':文字数が最小文字列長よりも短い場合は0で埋める
第6引数:フラグ'+':第2引数の正負にかかわらず常に符号を出力
第7引数:フラグ'-':数字を左に寄せる
戻り値:書きだした文字数('\0'は含まない)

5,6,7の引数に0/1以外の値が入っていた場合の動作は未保証です
(特に第6引数は0か1以外が入っていた場合は正常に動作しないです)


/* *** */

16以上の基数(たとえば32進法とか)に対応させたい場合は
一番最初のnumStrの中身を追加することで対応できます
対応している基数以上を設定された場合は正常に動作しないので
そのような可能性がある場合はsizeof等を使って確認するべきです

ま、そんなにクリティカルな場所はもっと確実な関数を使うべきです



0 件のコメント:

コメントを投稿