みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C言語で2桁Hex文字列を10進数値に変換する方法

C初心者です。よろしくお願いします。

測定器からシリアルで送られてくる2桁のHexデータ(リトルエンディアン)を10進数値に変換したいのですが、ネットでいろいろ調べてもよく解りません。
ネット上にあったプログラムを参考にして、次のようにやっています。

char d[3]; //受信データ

// データ受信処理後
int i=0, c=0, n;

while(d[i] != '\0'){
n = n * 0x10;
c = d[i++];

if((c >= '0') && (c <= '9')){
n += c - '0';
}
else if((c >= 'A') && (c <= 'F')){
n += c - 'A' + 10;
}
}
printf("%d\n",n);

結果を表示すると’0’になってしまいます。

どこがダメなのか、よろしくお願いします。

投稿日時 - 2011-03-15 00:22:47

QNo.6593603

すぐに回答ほしいです

質問者が選んだベストアンサー

>d[0], d[1], d[2] は間違いなく入っています。例えばd[0]=E5、d[1]=03という具合です。

なるほど、そういうことですね。
質問のところにあるプログラムは、HEX文字列を数値に変換するためのものです。
一方、測定器から送られてくるデータは、数値そのものです。

補足にあった配列の場合、リトルエンディアンですから、
0x03E5が、送信されたデータですね。
リトルエンディアンなので、プログラム的には面倒なのですが
2バイト固定ならば

int n ;
n = d [0];
n += d[1] << 8;

こんな感じで、変換できます。
(チェックはしていないので、不具合があったらフォローします。)

投稿日時 - 2011-03-15 02:52:24

お礼

早速有り難うございます。基本的にint型の変数に代入するだけで良いんですか!

早朝からまた現場がありますので、帰ってから早速試してみます。
有り難うございました。

投稿日時 - 2011-03-15 03:24:30

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(9)

ANo.9

すみません。
一つ間違い、というか仕様の不備といいますかがありました。

下位8bitが0の場合、(例: 0x0100)上位8bitが無視されてしまいます。
使用するバイト数が決まってるなら
/* whileではなく */
for(i=0;i<2; i++){
....
/* i ++ ; は削除*/
}
とかした方がいいですね。

投稿日時 - 2011-03-15 22:39:21

ANo.8

ちなみにシフトやビット演算では強制的に int に変換されるので, 明示的なキャストはなくてもいいです. まあ, 「読んだ人に親切」という点ではキャストした方がいいでしょうが.

あと, 「出来上がった値」が符号付きの場合にはしかるべく処理する必要がありますね.

あれ? 「受信データ」を char にする必然性がそもそもないような....

投稿日時 - 2011-03-15 11:28:37

お礼

ご指摘有り難うございます。実は送られてくるデータにはASCII、Hexデータが混在しています。そこで、一旦charに全部取り込んで、必要なデータを切り出して・・・という具合にやっています。具体的には先頭3バイトがASCIIで、次の4バイトがHexデータです。
受信データの検査もあるので、一旦全部取り込むようにしています。

投稿日時 - 2011-03-15 22:29:15

ANo.7

charが符号有りの可能性も考えて、元のを生かして作ればこんな感じでしょうか。

/* 0に初期化を忘れずに */
n=0;
while(d[i] != '\0'){
/* char→intに型変換し、&で8bitだけにする */
/* d[i]が負のとき、下から9bit目以降に1が入るため */
c = (int)(d[i]) & 0xff ;
/* 1文字当り8bitシフトして、|でビット毎の or を取る */
n |= c << (i * 8) ;
/* 現在のiを使いたいので、加算するのは最後 */
i ++ ;
}

投稿日時 - 2011-03-15 03:09:37

お礼

kmee 様 ほんとに丁寧な説明有り難うございます。
早朝から現場がありますので、帰ってから早速試してみたいと思います。
また、判らない時は質問させて頂きます。その節はまたよろしくお願いいたします。

投稿日時 - 2011-03-15 03:33:02

ANo.6

A#5です。

左シフトでキャストしわすれていました。
このままだと、上位バイトが0になると思います。
プログラムは以下のように訂正してください。

int n ;
n = d [0];
n += (int) d[1] << 8;

投稿日時 - 2011-03-15 02:59:02

お礼

有り難うございました。上手くいきました。ここ数日間の苦闘(?)がいったい何だったんだ!という感じです。

投稿日時 - 2011-03-15 22:17:45

ANo.4

No. 1 です。

> d[0], d[1], d[2] は間違いなく入っています。例えばd[0]=E5、d[1]=03という具合です。
ああ、やっぱり(^^;

d に入っているデータは値を文字列に変換したものではなく値そのものです。
データのフォーマットは回答 No.3 の kmee 氏が解説しているので、そのフォーマットを基に値を計算すればいいだけです。

投稿日時 - 2011-03-15 01:50:19

補足

>d に入っているデータは値を文字列に変換したものではなく値そのものです。

そーなんですか!やっと少しほぐれてきました。

>フォーマットを基に値を計算すればいいだけです。

どうプログラムすれば良いのでしょうか?1バイト目はE5ですから16*14+5、2バイト目は03ですから256*3で、229+768=997 とアスキー表を眺めながら考えるのですが、d[0]を上下4バイトずつに分けて計算するしかないように思うのですが、d[]を分割するなんて事出来るのでしょうか?
済みませんが、もう少しそこのところをお願い致します。

投稿日時 - 2011-03-15 02:45:24

お礼

ご指摘ほんとに有り難うございました。これまでもバイナリーデータとテキストデータの違いがわからず何度も参考書で調べていたのですが、ついに今回やっと判りました。
目からウロコとはこのことです(ちょっと違うかな?)。雲が晴れました!!

投稿日時 - 2011-03-15 22:38:09

ANo.3

> 2桁のHexデータ(リトルエンディアン)

とはどんなデータでしょうか?
リトルエンディアンは何についてなのでしょうか?

d[0] : '0','1',...'9','A','B',...'F'の16進を表わす文字(4bit分:下位?上位?)
d[1] : '0','1',...'9','A','B',...'F'の16進を表わす文字(4bit分:上位?下位?)
d[2] : '\0'

という16進数文字列なのでしょうか?

リトルエンディアンがビットの並びについてなら 「80」が「最下位ビットのみ1」ということにならないでしょうか?この場合、このプログラムでは正しく求まりません。
それとも、4bit単位の上下についてリトルエンディアンなのでしょうか?「10」が「最下位ビットのみ1」となるような。この場合もプログラムは正しくありません。

一般的な上位4bit+下位4bitという並びならば、 sscanfで%xを指定するとか、 strtolを使うとかするのが楽ではないでしょうか。

d[0] : 0x00~0xffまでの数値(8bit分:下位)
d[1] : 0x00~0xffまでの数値(8bit分:上位)
d[2] : '\0'
というデータなのでしょうか?(一般に、リトルエンディアンと言われたら、こういうデータを思い浮べますが)
これだとプログラムが変わってきます。


資料をよく調べる、デバッガを使う、途中経過をprintf等で出力してみる、等で、d[*]にどんな値が入っているのか、nがどんな変化するのかよく調べるのがよいでしょう。



細かいことを言えば、
> n += c - 'A' + 10;
これが期待通りに動くかどうかは、処理系依存です。

投稿日時 - 2011-03-15 01:31:34

お礼

早速有り難うございます。大変申し訳ありませんが、hitomura 様への補足で更に補足質問させて頂きます。

投稿日時 - 2011-03-15 02:26:41

ANo.2

ぱっとみですが、特におかしそうなところはないかな(^^;;

必ず、0になってしまうと言うことなので、
ループが一回も回っていない?と考えてます。

ブレイクポイントを打てるなら、whileループに入るところで配列の内容のチェック。
あと、if文での分岐で n+=.....の部分をきちんと通過しているか?
をチェックすべきかと。

投稿日時 - 2011-03-15 00:57:29

お礼

早速有り難うございます。

投稿日時 - 2011-03-15 02:23:14

ANo.1

回答(というか補足要求)の前にまず一言、ループに入る前に n を初期化しましょう。

さて、d[0], d[1], d[2] の値はどうなっているか確認しましたか?
確認できたなら一例でかまわないのでそれを補足に記述願います。

投稿日時 - 2011-03-15 00:47:43

補足

早速有り難うございます。
d[0], d[1], d[2] は間違いなく入っています。例えばd[0]=E5、d[1]=03という具合です。
d[2]には必ずNULLが入ります。

よろしくお願いします。

投稿日時 - 2011-03-15 01:19:53

あなたにオススメの質問