【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.22136

文字列から固定小数点数へ変換
投稿者---chu-(2005/07/26 17:45:20)


Win98, LSI-C

通信で受信した電文の解析用として、"-12.345"のような文字列を-12345という値に変換する関数を作成しています。
下記のようになんとか動くものはできました。
しかし、状態変数(status)を使っていたりcontinueを使っていたりで泥臭いソースになってしまった気がしています。
もっとスマートに組めないものでしょうか。

[関数の説明]
asc: 文字列
len: 変換最大長
point: 小数点以下第何位まで変換するか
endptr: 変換を終了した文字
status: 状態変数(0:符号,1:整数部,2:小数部)

[ソース]
#include <stdio.h>
#include <ctype.h>

typedef int bool;
#define TRUE  1
#define FALSE 0

long asc2fixed(const char *asc, int len, int point, char **endptr)
{
    long val;
    int status;
    int sign;

    val = 0;
    status = 0;
    sign = 1;
    for ( ; len > 0 && point > 0; asc++, len-- ) {
        if ( status <= 0 ) {
            if ( *asc == '+' ) {
                status = 1;
                continue;
            }
            else if ( *asc == '-' ) {
                sign = -1;
                status = 1;
                continue;
            }
        }
        if ( status <= 1 && *asc == '.' ) {
            status = 2;
            continue;
        }
        if ( !isdigit(*asc) )
            break;
        val = val * 10 + (*asc - '0');
        if ( status == 2 ) {
            point--;
        }
    }
    while ( point-- > 0 )
        val *= 10;
    val *= sign;
    if ( endptr != NULL )
        *endptr = (char *)asc;
    return val;
}

int main(void)
{
    const char *tbl[] = {
        "0Z",
        "1Z",
        "12Z",
        "123Z",
        "1234Z",
        "12345Z",
        "123456Z",
        ".0Z",
        ".1Z",
        ".12Z",
        ".123Z",
        "0.Z",
        "1.Z",
        "1.2Z",
        "1.23Z",
        "1.234Z",
        "+00.Z",
        "-10.Z",
        "+12.Z",
        "-12.3Z",
        "+12.34Z",
        "-12.345Z",
    };
    const int size = sizeof(tbl)/sizeof(tbl[0]);
    long val;
    char *end;
    int i;

    for ( i = 0; i < size; i++ ) {
        val = asc2fixed(tbl[i], 5, 2, &end);
        printf("%-8s → %-7ld : '%c'\n", tbl[i], val, *end);
    }

    return 0;
}

[実行結果]
0Z       → 0       : 'Z'
1Z       → 100     : 'Z'
12Z      → 1200    : 'Z'
123Z     → 12300   : 'Z'
1234Z    → 123400  : 'Z'
12345Z   → 1234500 : 'Z'
123456Z  → 1234500 : '6'
.0Z      → 0       : 'Z'
.1Z      → 10      : 'Z'
.12Z     → 12      : 'Z'
.123Z    → 12      : '3'
0.Z      → 0       : 'Z'
1.Z      → 100     : 'Z'
1.2Z     → 120     : 'Z'
1.23Z    → 123     : 'Z'
1.234Z   → 123     : '4'
+00.Z    → 0       : 'Z'
-10.Z    → -1000   : 'Z'
+12.Z    → 1200    : 'Z'
-12.3Z   → -1230   : 'Z'
+12.34Z  → 1230    : '4'
-12.345Z → -1230   : '4'




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:文字列から固定小数点数へ変換 22155 ぽこ 2005/07/26 22:58:37
<子記事> Re:文字列から固定小数点数へ変換 22173 かずま 2005/07/27 09:24:40
<子記事> Re:文字列から固定小数点数へ変換 22174 chu- 2005/07/27 10:05:59


No.22155

Re:文字列から固定小数点数へ変換
投稿者---ぽこ(2005/07/26 22:58:37)


>泥臭いソースになってしまった気がしています。
>もっとスマートに組めないものでしょうか。

参考にならないかも知れませんが、私はこう書きました。
状態変数ですが、状態の遷移が1→2→3以外存在しないので消しました。

コンパイル環境VC.net2003

long 
asc2fixed(const char *asc, int len, int point, char **endptr)
{
    long val = 0;
    int sign = '+';

    /* 符号の処理 */
    if(*asc == '+' || *asc == '-') {
        sign ^= *asc;
        asc++;
        len--;
    } else {
        sign = 0;
    }

    /* 整数部の処理 */
    for(; (len > 0) && isdigit(*asc); asc++, len--) {
        val = val * 10 + (*asc - '0');
    }

    /* 小数部の処理 */
    if(*asc == '.') {
        asc++;
        len--;
        for(; len > 0 && point > 0 && isdigit(*asc); asc++, len--, point--) {
            val = val * 10 + (*asc - '0');
        }
    }
    
    while ( point-- > 0 ) {
        val *= 10;
    }

    /* 処理がどこまで進んだかを返す */
    if ( endptr != NULL ) {
        *endptr = (char *)asc;
    }

    /* signが0なら正の数値 */
    return (sign == 0) ? val: -val;
}




この投稿にコメントする

削除パスワード

No.22173

Re:文字列から固定小数点数へ変換
投稿者---かずま(2005/07/27 09:24:40)


#include <stdlib.h>
#include <ctype.h>

long asc2fixed(const char *asc, int len, int point, char **endptr)
{
    char buf[256], *p = buf;

    if (*asc == '+' || *asc == '-') *p++ = *asc++, len--;
    while (len > 0  && isdigit(*asc)) *p++ = *asc++, len--;
    if (*asc == '.')
        for (asc++; --len > 0 && point > 0 && isdigit(*asc); point--)
            *p++ = *asc++;
    if (endptr) *endptr = (char *)asc;
    while (point-- > 0) *p++ = '0';
    *p = '\0';
    return strtol(buf, NULL, 10);
}



この投稿にコメントする

削除パスワード

No.22174

Re:文字列から固定小数点数へ変換
投稿者---chu-(2005/07/27 10:05:59)


なるほど、お二人とも符号、整数、小数と順々に処理していますね。
明らかに処理の流れが読みやすいです。
これなら、先頭のスペースは飛ばす等の機能追加も簡単そう。

どうやら私は「val=val*10+(*asc-'0');」このコードを1ヶ所にしようと固執しすぎていたようです。
改良の参考にさせていただきます。

ありがとうございました。



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧