アプリ版:「スタンプのみでお礼する」機能のリリースについて

こんにちは。
お世話になります。

16進数を10進数文字列に変換する処理を作りたいのですが
方法が分かりません。
提供されている関数は使わずに変換する方法を知っている方がいたら教えていただきたいです。
以下は10進数を16進数に変換する関数を作ったものです。


void SetBinHex(BYTE Bin,BYTE *buff)
{
/*16進の変換*/
*(buff)=Bin/16;
*(buff+1)=Bin%16;
if(*(buff)>9)
*(buff)=*(buff)+0x37;
else
*(buff)=*(buff)+0x30;
if(*(buff+1)>9)
*(buff+1)=*(buff+1)+0x37;
else
*(buff+1)=*(buff+1)+0x30;

return ;
}

よろしくお願いします。

A 回答 (6件)

★16進数とは整数ですよね。


・それを 10 進数に変換するなら 10 で割ったり、10 で割ったあまりを使って
 10進文字列を作成します。質問に書かれている C ソースでは最初 16 で
 割っているため正しくありません。
 次のようにしてみてください。

サンプル:
void SetBinHex( BYTE Bin, BYTE *buff )
{
 BYTE *hp = buff; ←先頭ポインタ
 BYTE *tp = buff; ←末尾ポインタ
 BYTE tmp; ←一時変数
 
 // 16進整数を10進文字列に変換
 *tp++ = ((Bin % 10) + '0'); Bin /= 10; ←1桁目
 *tp++ = ((Bin % 10) + '0'); Bin /= 10; ←10桁目
 *tp++ = ((Bin % 10) + '0'); Bin /= 10; ←100桁目
 *tp-- = '\0';
 // 文字列の左右を入れ替え
 for ( ; hp < tp ; hp++, tp-- ){
  tmp = *hp;
  *hp = *tp;
  *tp = tmp;
 }
}

解説:
・n進整数からm進文字列に変換するときは、整数値の下位の桁から割っていき
 文字列に変換するのが一般的です。文字列にする際に書き込む位置をポインタで
 移動しますがこの場合は下位の桁から順に文字列に変換されます。
 そこで文字列に変換した後に文字列の左右を入れ替える必要が出てきます。
 この処理をなくすと 0xCD の値が 502 となります。
 正しくは文字列を左右入れ替え205 とします。
・例えば 0xCD は 10 進数で 205 です。
 変換の考え方は
 ステップ1
  205 % 10→'5'
  205 / 10→20
 ステップ2
  20 % 10→'0'
  20 / 10→2
 ステップ3
  2 % 10→'2'
  2 / 10→0
 ステップ4
  5、0、2 という数を左右入れ替えて
  2、0、5 となり正しく変換されます。
・以上。下の『参考URL』もどうぞ。こちらは itoa の例です。

参考URL:http://oshiete1.goo.ne.jp/qa3355671.html
    • good
    • 0

ごめんなさい、訂正です。



>ここは、*buff = *buff - 10 + 'A'; と表現すべきです。(最適化はコンパイラーがやります)

BYTE型がunsignedだとバグる気がするので、*buff + ('A' - 10);の方が安全ですね。
    • good
    • 0

元のプログラムが汚くて理解できないような気がする、、、



プログラム自体は、文字コードがASCIIであることを期待しているようなので、処理系依存になります。つまり、そもそもあまり褒められたもんじゃないということ。

それと、このサンプル関数のやっていることは、「10進数を16進数に変換」ではなく、整数型(内部表現は二進整数)を16進文字列に変換しているのです。

>if(*(buff)>9)
> *(buff)=*(buff)+0x37;

ここは、*buff = *buff - 10 + 'A'; と表現すべきです。(最適化はコンパイラーがやります)

結果は、*buffの値が10のときに文字'A' (二進表現で0x41)が代入され、11のときには'B'が代入され、、、ます。

>else
> *(buff)=*(buff)+0x30;

ここは、*buff = *buff + '0';
同じく整数値として0のとき文字'0' (二進表現で0x30)が代入され、、、

ということです。

厳しく見ると、型を二重に取って居るので暗黙のキャストでバグになりやすいプログラムです。No.2さんがおっしゃるように、中間値はintで取ったほうがよいでしょう。(shortにしてもよほど小さいプロセッサでなければパフォーマンス上のメリットはありません)

もう一点。文字列に変換するといいながら、最後にnull値を挿入していないので、このままCの標準関数などで扱うと暴走します。安全なコーディングとしては、char *buffと宣言するのではなく、char buff[2]等と宣言するか、3文字目に'\0'を格納するべきです。

で、演習の課題に戻るわけですが、サンプルプログラムは8ビットアンサインド整数を16進文字列に変換するプログラムです。これを見て作れということは、課題の意図は8ビットアンサインド整数を10進文字列に変換せよという事かと思いますが、それなら16を10に変えて、3桁目を想定するだけですね。ゼロサプレスをしなくて良いなら、元のプログラムをほぼコピペで出来ると思いますけど。

ただ、BYTEの型定義にunsignedが入ってないとバグるかもしれませんのでお気をつけて。
    • good
    • 0

追記。



ANo.1の回答に書いた関数で「16進文字列を数値にする」のが出来れば、質問文のSetBinHexをちょっと改造したのと組み合わせて「16進文字を10進文字列にする」のが出来ます。

改造は「16で割った商と余りで2桁作る」のを「100で割った商、10で割った商、10で割った余りで3桁作る」だけです。
    • good
    • 0
この回答へのお礼

ありがとうございます。
参考になります。考えて見ます。

お礼日時:2007/09/27 16:37

何点かご質問させて下さい。


この関数、
 問答無用で隣のアドレスまで破壊してますが考慮した作りになってますか?
 なぜ引数をBYTE型にしたのでしょうか?
 計算中もbuffを使用していますが、その意図は?(見にくいので計算結果だけを入れるだけじゃダメなのか?)
10進数変換関数、
 引数と戻り値はどうしますか?
 変換前16進数の大文字小文字の判断は?

この関数は質問者様が作成されたのでしょうか?
これが作れるのであれば、10進数変換も十分作れる実力があると思いますが?
    • good
    • 0
この回答へのお礼

お返事ありがとうございます。

>問答無用で隣のアドレスまで破壊してますが考慮した作りになってますか?

隣のアドレスを破壊しているのですか??
すみません。分かっていませんでした。


>なぜ引数をBYTE型にしたのでしょうか?

最終的には構造体にchar型でメンバを作り結果を入れようとしています。なぜBYTE型は分かりません。16進への変換はこれで覚えろと教えられました。
 
>計算中もbuffを使用していますが、その意図は?(見にくいので計算結果だけを入れるだけじゃダメなのか?)

変換をするためだけの関数となっているので、この関数内で直接入れないようにするため、わざとbuffを使っています。


>10進数変換関数、引数と戻り値はどうしますか?変換前16進数の大文字小文字の判断は?

説明不足で申し訳ありません。
入ってくるデータは現在作成中のプログラムでは数字以外は入れないようにしています。

>この関数は質問者様が作成されたのでしょうか?
これが作れるのであれば、10進数変換も十分作れる実力があると思いますが?

これはサンプルとしていただいたものです。
きちんとこのプログラムを理解できていないため皆さんにご迷惑をおかけしてしまい、申し訳ありません。

お礼日時:2007/09/27 16:33

逆をやれば良いだけですが、何が判らないのですか?



BYTE SetHexBin(BYTE *buf)
{
return (buf[0]>'9'?buf[0]-'7':buf[0]-'0')*16+(buf[1]>'9'?buf[1]-'7':buf[1]-'0');
}
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございます。
このプログラムはサンプルとして作っていただいたものです。

このサンプルを見てポインタをずらして1つずつ文字にしているという漠然なことしか分かっていません。
コメントをつけてみようと思います。

お礼日時:2007/09/27 16:20

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!