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

このQ&Aのポイント
  • C初心者のため、C言語で2桁Hex文字列を10進数値に変換する方法がわからない。
  • ネットでの調査や既存のプログラムを参考にして試したが、結果が期待通りにならずに困っている。
  • 質問者は、受信データの処理中に何が問題なのかを知りたいと思っている。
回答を見る
  • ベストアンサー

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’になってしまいます。 どこがダメなのか、よろしくお願いします。

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

  • ベストアンサー
回答No.5

>d[0], d[1], d[2] は間違いなく入っています。例えばd[0]=E5、d[1]=03という具合です。 なるほど、そういうことですね。 質問のところにあるプログラムは、HEX文字列を数値に変換するためのものです。 一方、測定器から送られてくるデータは、数値そのものです。 補足にあった配列の場合、リトルエンディアンですから、 0x03E5が、送信されたデータですね。 リトルエンディアンなので、プログラム的には面倒なのですが 2バイト固定ならば int n ; n = d [0]; n += d[1] << 8; こんな感じで、変換できます。 (チェックはしていないので、不具合があったらフォローします。)

NamakeGamo
質問者

お礼

早速有り難うございます。基本的にint型の変数に代入するだけで良いんですか! 早朝からまた現場がありますので、帰ってから早速試してみます。 有り難うございました。

その他の回答 (8)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.9

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

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

ちなみにシフトやビット演算では強制的に int に変換されるので, 明示的なキャストはなくてもいいです. まあ, 「読んだ人に親切」という点ではキャストした方がいいでしょうが. あと, 「出来上がった値」が符号付きの場合にはしかるべく処理する必要がありますね. あれ? 「受信データ」を char にする必然性がそもそもないような....

NamakeGamo
質問者

お礼

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

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.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 ++ ; }

NamakeGamo
質問者

お礼

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

回答No.6

A#5です。 左シフトでキャストしわすれていました。 このままだと、上位バイトが0になると思います。 プログラムは以下のように訂正してください。 int n ; n = d [0]; n += (int) d[1] << 8;

NamakeGamo
質問者

お礼

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

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.4

No. 1 です。 > d[0], d[1], d[2] は間違いなく入っています。例えばd[0]=E5、d[1]=03という具合です。 ああ、やっぱり(^^; d に入っているデータは値を文字列に変換したものではなく値そのものです。 データのフォーマットは回答 No.3 の kmee 氏が解説しているので、そのフォーマットを基に値を計算すればいいだけです。

NamakeGamo
質問者

お礼

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

NamakeGamo
質問者

補足

>d に入っているデータは値を文字列に変換したものではなく値そのものです。 そーなんですか!やっと少しほぐれてきました。 >フォーマットを基に値を計算すればいいだけです。 どうプログラムすれば良いのでしょうか?1バイト目はE5ですから16*14+5、2バイト目は03ですから256*3で、229+768=997 とアスキー表を眺めながら考えるのですが、d[0]を上下4バイトずつに分けて計算するしかないように思うのですが、d[]を分割するなんて事出来るのでしょうか? 済みませんが、もう少しそこのところをお願い致します。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.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; これが期待通りに動くかどうかは、処理系依存です。

NamakeGamo
質問者

お礼

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

回答No.2

ぱっとみですが、特におかしそうなところはないかな(^^;; 必ず、0になってしまうと言うことなので、 ループが一回も回っていない?と考えてます。 ブレイクポイントを打てるなら、whileループに入るところで配列の内容のチェック。 あと、if文での分岐で n+=.....の部分をきちんと通過しているか? をチェックすべきかと。

NamakeGamo
質問者

お礼

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

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

回答(というか補足要求)の前にまず一言、ループに入る前に n を初期化しましょう。 さて、d[0], d[1], d[2] の値はどうなっているか確認しましたか? 確認できたなら一例でかまわないのでそれを補足に記述願います。

NamakeGamo
質問者

補足

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

関連するQ&A

  • 独学で最近c言語を始めたものです。10進数を16進数に変換するプログラ

    独学で最近c言語を始めたものです。10進数を16進数に変換するプログラムを作りました。 しかしコンパイルしてもエラーは出ないのですがprintfの部分で配列の結果のみが出ません。 如何せん、独学ですので気付かないところで簡単なミスをしているかもしれませんが、分かる方がいましたご教授ください。 #include<stdio.h> int main() { static char data[16]= {'1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; char hex[5]; short dec,num,i; for(;;){ for(i=0;i<=3;i++) hex[i]=' '; hex[4]='\0'; printf("10進数を入力してください。>>"); scanf("%d",&dec); if(dec==0) break; for(i=3;dec!=0;i--){ num=dec%16; dec/=16; hex[i]=data[num]; } printf("16進数は%sです\n",hex); } }

  • 文字列から文字を探す

    以下のプログラムです。 #include <stdio.h> main () { char s[]="I love cat and dog."; char c='a'; char *p=s; int n=0; printf("\"%s\"の中から\'%c\'を探します。",s,c); while(*p != '\0') { if(*p == 0) { printf("%d文字目で発見しました。\n",p-s+1); n++; } p++; } if(n == 0) printf("1つも見つかりませんでした。\n"); else printf("全部で%d個見つかりました。\n",n); } C言語の本で勉強しています。 ・p-s+1の意味がわかりません。 ここには何が割り当てられているのでしょうか? ・*pとpの違いもあいまいです。 ・\"%s\"は「"」を印刷するためには必要なのでしょうか? どう質問していいのかもわからないのですが、よろしくお願いします。

  • c言語 文字列と配列

    #include<stdio.h> int charlen(int n); void cap2sml(int b); int main() { char a[100],b[100]; int n,i; /*Input CARACTERS*/ printf("CAPITAL?\n"); fgets(a,100,stdin); charlen(n); printf("total cahrs=%d\n",n); //printf in main cap2sml(i); printf("small=%s\n",b); return(0); int charlen(int n) n=0; while(1){ if(a[n]=='\0') break; n++; } void cap2sml(int b) int i; for(i=0;a[i]!='\0';i++){ b[i]=a[i]+0x20; } b[i]='\0' } のプログラムでエラーがでるのですが、どこを直せばよいでしょうか? ユーザー関数を使い文字列(大文字)を入力したときの文字列の長さと大文字を小文字に変化するプログラムです

  • C言語のプログラミングで困っています

    C言語を勉強しています。まだまだ初心者で分からないことだらけなのですが、今回はファイル入出力の部分が分からず苦戦しています。 『100個の実数が入った2つのテキストファイルから数値を読み込み、  絶対値を求めるなどの計算をする』プログラムを作成しているのですが、 コンパイルし実行すると強制終了してしまいます。 プログラムは、 void main(void) { FILE *fp; double c[50000];   double d[50000];   double e[50000]; int n = 0;   int m = 0;   int i = 0;   char fname[80];   char fname2[80]; printf("ファイル名 : ");    gets(fname); if((fp = fopen(fname, "r")) == NULL){ printf("ファイルがオープンできません\n"); exit(1); } printf("\n"); while (fscanf(fp,"%lf",&c[i])!=EOF){ printf("%3d : %3lf",++n,c[i]); printf("\n"); i++; } printf("\n"); i=0; n=0; printf("ファイル名 : ");    gets(fname2); if((fp = fopen(fname2, "r")) == NULL){ printf("ファイルがオープンできません\n"); exit(1); } printf("\n"); while (fscanf(fp,"%lf",&d[i])!=EOF){ printf("%3d : %3lf",++n,d[i]); printf("\n"); i++; } …(以下計算) のようになっています。 整数のデータで計算を行うと、正常に動くのですが…。 コンパイルしてもエラーが出ないので、どこが悪いのかわからず困っています。 どなたか教えていただけないでしょうか。お願いしますm(_ _)m

  • C言語で複数列のデータを1列のみ読み込みたい

    行m列の任意のデータの処理を行うプログラムで, 列ごとの統計を行うためにm列目のデータを取り出したいのですが,うまくいきません. どのようなコードを書けばいいでしょうか? 自分で作ってみたのは以下のようなプログラムです(ファイルを開いて→m列目の読み込みの部分) EOFを使っているためか,行数のiには全データ数が入ってしまいます. void main (void) { FILE* fp; int i, j; i=0, j=0; char FilePath[500]; char Folder[100]; char File[50]; printf("Folder Name:"); scanf("%s",&Folder); printf("File Name:"); scanf("%s",&File); sprintf(FilePath,"%s/%s",Folder,File); if(( fp = fopen (FilePath,"r")) == NULL){ printf("cannot open '%s'\n", FilePath); exit(1); } //ここまではうまく動きます while (fscanf(fp, "%lf", &A[i][0]) != EOF{ i++; } while (fscanf(fp, "%lf", &A[0][j]) != EOF){ j++; } printf("A[%d][%d]", i, j); int n, m;              //n,mはこの後for文で使いたいので登場してもらいました printf("input 'n':"); scanf("%d", &n); printf("input 'm':"); scanf("%d", &m); }

  • C言語初心者です。

    #include <stdio.h> int main() { int b[100]; int i, n; int a, r, data; int count=0; printf("Please input two integers:"); fflush(0); scanf("%d %d", &a, &r); if(a<=0 || r<=1){ printf("Error\n"); } else{ for(n=0; b[n]<=80.0; n++){ if(n==0){ b[0]=0; count++; } else { for(i=0; i<=n-1; i++){ data*=r; } b[n]=a*data; printf("%d ", b[n]); count++; } } printf("\n"); for(; count>0; count--){ printf("%d ", b[count]); } } return 0; } windows8でeclipseを使ってC言語を書いてます。 eclipse上だと何もエラーが表示されてないのですが、実行し、 Please input two integers: と表示された後、適当な数字2つを入力しても何も反応しません。 稚拙な質問ですいません。どなたか原因を教えてください。

  • C言語の配列の使い方について質問です。

    以下のプログラムを配列を使って見やすくしたいのですが、どのように作ったら良いでしょうか? 宜しくお願いします。 #include<stdio.h> int main(void) { int a, b, c, d, e, f, g, h, i, j, k, l, m ,n, o; /*5段目の処理*/ for(a = 1; a <= 15; a++) { for(b = 1; b <= 15; b++) { if(a == b) continue; for(c = 1; c <= 15; c++) { if(a == c || b == c) continue; for(d = 1; d <= 15; d++) { if(a == d || b == d || c == d) continue; for(e = 1; e <= 15; e++) { if(a == e || b == e || c == e || d == e) continue; // printf("%d %d %d %d %d\n", a, b, c, d, e); ////4段目//// if(a>b){ f=a-b; } else if(a<b){ f=b-a; } if(b>c){ g=b-c; } else if(b<c){ g=c-b; } if(c>d){ h=c-d; } else if(c<d){ h=d-c; } if(d>e){ i=d-e; } else if(e<d){ i=e-d; } // printf(" %d %d %d %d \n", f, g, h, i); /////3段目//// if(f>g){ j=f-g; } else if(f<g){ j=g-f; } if(g>h){ k=g-h; } else if(g<h){ k=h-g; } if(h>i){ l=h-i; } else if(h<i){ l=i-h; } // printf(" %d %d %d \n", j, k, l); /////2段目//// if(j>k){ m=j-k; } else if(j<k){ m=k-j; } if(k>l){ n=k-l; } else if(k<l){ n=l-k; } // printf(" %d %d \n", m, n); /////三段目///// if(m>n){ o=m-n; } else if(m<n){ o=n-m; } // printf(" %d \n", o); if(a != b != c != d != e != f != g != h != i != j != k != l != m != n != o){ printf("%d %d %d %d %d\n", a, b, c, d, e); printf(" %d %d %d %d \n", f, g, h, i); printf(" %d %d %d \n", j, k, l); printf(" %d %d \n", m, n); printf(" %d \n", o); } } } } } } }

  • 文字列 数 変換

    数字列を数に変換できなかった男です。 以下はコンパイルエラー patn.c: In function 'input': patn.c:9:3: warning: function returns address of local variable [-Wreturn-local- addr] return (str); ^ 以下は実行後、 数を入力してください。 123.456 ・・,( 0.000000 0 0 以下は書いたプログラムです。 #include<stdio.h> #include<stdlib.h> char *input(void){ char str[100]; printf("数を入力してください。\n"); scanf("%s",str); return (str); } int main(void){ char *a; double d; int i; long l; a=input(); printf("%s\n",a); d=atof(a); i=atoi(a); l=atol(a); printf("%f %d %ld",d,i,l); return(0); } 関数input()にchar *str2; str2=str; return(str2);としても、実行後の表示はおかしいです。 123.456 123 123.456と表示したいです。御指摘お願いします。

  • C言語 ハノイの塔

    #include<stdio.h> void hanoi(int n,char a,char b,char c); int main(void) { int n=3; printf("円板の枚数 ⇒ " ); hanoi(n,'a','b','c'); return 0; } void hanoi(int n,char a,char b,char c) { if(n > 0){ hanoi(n - 1,a,c,b); printf("%d番の板を %c から %c に移動\n",n,a,b); hanoi(n - 1,c,b,a); } } このときの再帰の処理がわかりません。。 再帰の間にprintfがあるのでどこがつながっているのか順番がわかりません。 具体的な数値の手順を教えてください。

  • 文字列の照合についての質問(C言語)

    こんにちは<_ _> 文字列の照合に関する質問です。 データを探索するプログラムを作っていましたが 既存データと入力データの照合ができません。 #include<stdio.h> #include<string.h> #define N 10 int main(void) { static struct girl{ char *name; int age; }a[]={"Ann",18,"Rolla",19,"Nancy",16,"Eruza",17,"Juliet",18, "Machilda",20,"Emy",15,"Candy",16,"Ema",17,"Mari",18}; char key[20]; int i; printf("検索するdata ? : "); scanf("%s",key); for(i=0;i<N;i++){ ここの部分です if(a[i]==key){ break; } } printf("%s %d",a[i],a[i]); return 0; } 照合するにはどうしたらいいのでしょうか? (#include<stdio.h> から  int i;までは変えてはいけないと問題にあります。)

専門家に質問してみよう