- ベストアンサー
32ビット長のものを8ビット長の配列に格納して戻すプログラムについて
- プログラミング初心者のため、32ビット長のものを8ビット長の配列に格納し、再度32ビット長に戻すプログラムに関する質問です。
- 質問者は現在のプログラムが正しく動作していないため、どこが間違っているのかを知りたいとのことです。
- 質問の中で与えられたプログラムには、32ビット→8ビットと8ビット→32ビットへの変換処理が含まれています。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
こんにちは。#4、#8です。 #8の補足について。 > メッセージ b[0]=1 b[1]=2 b[2]=3 b[3]=4 を送ったとすると > パソコン上で > 1 2 3 4 > と表示されます。 > 次に a = b[0]+b[1]*256+b[2]*256*256+b[3]*256*256*256 をしたあとに > メッセージ aを送ると > パソコン上で > 1 2 3 4 > と表示されるはずです。 > しかし、実際にはそうはいきませんでした。 : > 8bit→32bitの動作をしたあとにaをメッセージにしたところ(実際の値は覚えて > いないのですが、上の例を使うと)、 > 1 2 255 255 > と表示されました。 上記を記述し直すと、 <変数の宣言> uint32_t a; ・・・ 符号無し32bit整数 uint8_t b[4]; ・・・ 符号無し8bit整数の配列 ※数値のバイトオーダーはリトルエンディアンと仮定 <変換前データ> a = 0x04030201; の状態で、変換後のデータをパソコン側で表示させた場合、 <変換後データ> b[0] = 0x01; (10進値= 1) b[1] = 0x02; (10進値= 2) b[2] = 0x03; (10進値= 3) b[3] = 0x04; (10進値= 4) 変数 a の値を【下位バイト→上位バイト】の順で表示した場合 1、2、3、4 ※変数の内部値(32bitの16進値)は、a = 0x04030201 という表示を想定していたが、実際には、 <変換後データ> b[0] = 0x01; (10進値= 1) b[1] = 0x02; (10進値= 2) b[2] = 0x03; (10進値= 3) b[3] = 0x04; (10進値= 4) 変数 a の値を【下位バイト→上位バイト】の順で表示した場合 1、2、255、255 ※変数の内部値(32bitの16進値)は、a = 0xFFFF0201 と表示されたということでしょうか? だとした場合、変換後の変数 a の上位2バイト分が、何処かの段階でデータ落ち (格納されていない、送信されていない、または、受け取れていない)状態が発生 しているのかもしれません。 何処かの段階というのは、 (1)通信機器側のデータ変換処理 (2)通信機器側のパソコン向けのデータ送信処理 (3)パソコン側の通信機器からのデータ受信処理 の各ケースが考えられます。 以下は、上記各ケース別の確認事項及び対策方法などです。 ■上記(1)のケース この場合、やはり以下の変換式が問題かもしれません。 // 8bit→32bit a = b[0]+b[1]*256+b[2]*256*256+b[3]*256*256*256; ご使用のコンパイラ(通信機器用プログラムの開発環境)での、リテラル値(定数値) どうしの演算が、16bit整数値として扱われた場合、 b[2]*256*256 および b[3]*256*256*256 の演算段階で、16bit整数のオーバーフローが発生して、結果的に変数 a には、 上位桁(上位2バイト分)が欠落した値が格納されているのかもしれません。 ※式中の変数 b[] は8bit整数のため、暗黙のデータ拡張がされても16bit整数 として演算されているのかもしれません。 ※ただし、欠落した部分には、255 ではなく 0 が格納されるかもしれませんが? 注)処理系により暗黙の算術変換の仕様も異なると思いますので、上記の内容が 今回のケースに当てはまるとは限りません。 試しに、上記の演算式を下記のように変更して再実行した場合、何か変化が 表れるかもしれません。 /* 8bit→32bit (修正版) */ a = b[3]; a = a*256 + b[2]; a = a*256 + b[1]; a = a*256 + b[0]; 上記の場合、演算式中に、32bit整数の変数が含まれているため、暗黙の データ拡張が行われ、32bit整数として演算され、変数 a にも正しい値が 格納されるかもしれません。 ■上記(2)のケース ◎データ送信処理について ・送信データサイズが正しいか確認 ・エラーが発生していないか確認 ■上記(3)のケース ◎データ受信処理について ・想定データサイズ分受信しているか確認 ・エラーが発生していないか確認 以上です。
その他の回答 (8)
こんにちは。 #4です。 以下、#4の補足について。 ================================================== > また、確認の仕方なのですが、このプログラムは通信機器に用いているので、 > printfのような動作ができません。パソコンにつないである機器で受信し、 > パソコン上のソフトで表示し確認しています。 ファームウェア(組み込み機器に実装されたソフトウェア)という事でしょうか? 通信機器のインターフェース(対パソコンに対して)はどのようなものですか? <通信機器のインターフェースの例> ・RS-232C ・LAN(TCP/IPなど) ・その他 > うまくいっていないところなのですが、 > 意図した出力がならないということです。b[0]~b[3]には、意図した > 値が格納されているのが確認できています。 『意図した出力がならない』とは、どのような値が出力されたのでしょうか? ・バイト順が違う ・想定外の値になっている ・【バイナリ値→文字】等の変換を行っていた場合に文字化けしている b[0]~b[3]の値は、どのように確認されたのでしょうか? ・パソコン側で受信したデータを確認した ・回線モニタなどで確認した ================================================== データ不具合の原因は幾つか考えられると思います。 1)数値の変換処理が上手くいっていない ・b[0]~b[3] ⇒ a への変換は正しいか? ・バイトオーダー(リトルエンディアン、ビッグエンディアン)は合っているか? 2)通信処理(送受信処理)が上手くいっていない ※この場合、上記1)の変換処理は上手くいっていると仮定して。 <機器間の通信仕様の確認事項> ◎RS-232Cの場合 ・通信速度(ボーレート) ・データ長(8ビット、7ビット) ・ストップビット(1ビット、1.5ビット、2ビット) ・パリティの有無(パリティなし、偶数パリティ、奇数パリティ) ・フロー制御(ハードウェア)の有無 など。。。 <機器間の通信プロトコルの確認事項> ・送受信データのやり取り手順(データ送信に対する応答の有無など) ・フロー制御(ソフトウェア)の有無 <その他の確認事項> ・数値データの送出順(下位バイトから出力 or 上位バイトから出力) ・送信側と受信側のバイトオーダー(リトルエンディアン、ビッグエンディアン) 3)ハードの不具合 ================================================== 通信の不具合の確認方法ですが、環境があればの話しですが、 ・RS-232Cの場合なら、回線アナライザ(回線モニタ)などで確認。 ・TCP/IPの場合なら、パケットアナライザ(パケットモニタ)などで確認。 などの方法で、まず、 ・送信側(送信データ、送信処理)が悪いのか ・受信側(受信データ化け、受信処理)が悪いのか ・ハードの不具合 などを切り分けた方が良いと思います。 ================================================== 以上、ざっと気付いた点など明記してみました。参考まで。。。 ※的外れの内容でしたらすみません。
お礼
何度も回答いただき、また丁寧な回答本当にありがとうございます。説明不足が続き申し訳ありません。 はい、ファームウェアです。また、インターフェースについてですが、無線機器1つとパソコンをUSBケーブルでつなげ、その無線機器が受信したメッセージをパソコン上のソフトウェアで表示するといった確認方法をとっています。また、そのソフトウェアの表示の仕方なのですが、受信したデータをすべて8ビット長のもので表示していきます。16ビットのものは2つ分を使い、32ビットのものなら4つ分使って表示します。なので、メッセージがaのときとb[0]~b[3]を送ったときは同じ結果が表示されるはずなのです。たとえば、 メッセージ b[0]=1 b[1]=2 b[2]=3 b[3]=4 を送ったとすると パソコン上で 1 2 3 4 と表示されます。 次に a = b[0]+b[1]*256+b[2]*256*256+b[3]*256*256*256 をしたあとに メッセージ aを送ると パソコン上で 1 2 3 4 と表示されるはずです。 しかし、実際にはそうはいきませんでした。そこで、プログラミング的に計算が間違っているのかと思い質問させてもらいました。 ちなみに 32bit→8bitの動作をする前のaとその動作をしたあとのb[0]~b[3]を送ったときは同じものが表示され、8bit→32bitの動作をしたあとにaをメッセージにしたところ(実際の値は覚えていないのですが、上の例を使うと)、 1 2 255 255 と表示されました。 通信処理やハードの不具合も考えてみたいと思います。
C言語のサブセットのような言語でしょうか?できれば、aの初期値と、b[0]~b[3]、および、aの最終値の「期待していた値」と「実際の値」の両方を記述して質問すると、回答も得られやすいと思います(できればソースもあればベター)。 Windows上でMinGWのgccでやってみました。できるだけ古いコンパイラでも通るようにしたつもりですが、まともなc言語プログラムは10年以上やっていなかったので変かもしれません。実質上、質問者様と同様の処理(printfは使ってますが)ですが、こういう場合はシフト演算子やビット演算子を使った方が自然だと思います(効率も良いですし)。これだと、考えたとおりの結果になりました。 --- #include <stdio.h> int main(void){ unsigned int a = 0x01234567; unsigned int aa; unsigned char b[4]; int i; printf("sizeof( unsigned int )=%d\n", sizeof( unsigned int ) ); printf("sizeof( unsigned char )=%d\n", sizeof( unsigned char ) ); /* 32bit -> 8bit */ for( i=0,aa=a; i<4; ++i,aa>>=8 ){ b[i] = (unsigned char)(aa & 0xff); printf("b[%d]=0x%x\n", i, b[i]); } /* 8bit -> 32bit */ aa = b[0] | b[1]<<8 | b[2]<<(8*2) | b[3]<<(8*3); printf("aa=0x%x\n", aa); if( aa == a ){ printf("復活成功\n"); } else { printf("復活失敗\n"); } return 0; } ---実行結果 sizeof( unsigned int )=4 sizeof( unsigned char )=1 b[0]=0x67 b[1]=0x45 b[2]=0x23 b[3]=0x1 aa=0x1234567 復活成功 --- あと、処理系によってはこんな手もあります。 --- union c{ unsigned int a_copy; unsigned char b_copy[4];}; union c cc; /* 32bit -> 8bit */ cc.a_copy = a; --- まさかとは思いますが、intのサイズは何ビットでしょう?b[3]*256*256*256あたりで、演算がオーバーフローしたとか(普通はないはずですが)。
お礼
回答ありがとうございます。 値なのですが、実際にプログラムを動かす機器が学校にしかなくてちょっとわからない値もあるのですが、 aの初期値 uint32_t a = 20100715; uint8_t b[4]; 以上のようではあったと思います。 わざわざサンプルプログラムまで書いてくださいましてありがとうございます。 シフト演算、ビット演算についても参考にしたいと思います。
- noyuo
- ベストアンサー率39% (33/84)
memcpy でもできると思いますが、 好みでは、 すべて、unsigned で、 for (idx=0; idx<4; idx++){ bb[idx] = aa & (unsigned char)0xff; aa = aa >> 8; } aa = ((((bb[3]*256)+bb[2])*256+bb[1])*256)+bb[0]); というビットシフトでも何をしたいのかが判りやすいと思います。 ご参考まで。
お礼
回答ありがとうございます。 プログラミング初心者でぱっと見だと、原理がよく理解できていないので、 じっくり見て理解し、参考にしたいと思います。 わざわざありがとうございました。
- hashioogi
- ベストアンサー率25% (102/404)
変数a, b の取り方ですが、片方がsignedで他方がunsignedだとうまくいかない場合がある。
お礼
回答ありがとうございます。 確認したところ、ともに符号なしで宣言していました。
こんにちは。 ご提示のロジック(変換手順)そのものは、間違っていないと思います。 > うまくいかなくて困っています。 これは、どこが上手くいっていないのでしょうか? コンパイル時のエラーでしょうか、または、実行時のエラー、もしくは意図した出力に なっていないのでしょうか? #3さんの言われるとおり、以下のような変数定義の仕方とか、数値の扱い方に問題 があるのかもしれません。 ◎変数定義の注意点 ・符号付き と 符号無し の違いを考慮する。 ◎数値の入力および出力の仕方の注意点 ・scanf、printf等での 書式指定子 と 実際の参照値の型を合わせる。 などの注意が必要かもしれません。 #1、#2さんと被ってしまいますが、当方でもサンプルプログラムを作成してみました。 ※C言語で作成してあります。 宜しければ検証してみて下さい。 注)このサンプルプログラムでは、 ・バイトオーダーがリトルエンディアン ・int型のサイズが32bit の処理系を想定しています。 ■サンプルソース(※以下のリンク先参照) http://ideone.com/2jaFQ 以上です。
お礼
丁寧な回答ありがとうございます。 説明不足で申し訳ありません。うまくいっていないところなのですが、 意図した出力がならないということです。b[0]~b[3]には、意図した 値が格納されているのが確認できています。 また、確認の仕方なのですが、このプログラムは通信機器に用いているので、 printfのような動作ができません。パソコンにつないである機器で受信し、 パソコン上のソフトで表示し確認しています。 変数定義は両方とも符号なしになっています。また、数値の入力ですが、 aの値はscanfで入力するのではなくあらかじめ宣言しています。 サンプルソースを参考に検証してみたいと思います。
- kmee
- ベストアンサー率55% (1857/3366)
言語は何ですか? C言語かそれに類するもののようですが。 また、a, b[4]はその言語でどんな変数の型になっていますか? 型が符号付き整数だとすると、計算あわなくなると思います。
お礼
回答ありがとうございます。言語はc言語に類するものです。 変数の型は以下のようになっています。 uint32_t a; uint8_t b[4]; 確認したところ、一応、両方とも符号なし整数になっていました。
- himajin100000
- ベストアンサー率54% (1660/3060)
http://ideone.com/rAleh めんどうだからってあまり意識せずに書いていたらビッグエンディアンになってたな。 リトルエンディアンだとこうかな?(iと3-iが入れ替わった)
お礼
回答ありがとうございます。 わざわざサンプルソースありがとうございます。 参考にしたいと思います。
- himajin100000
- ベストアンサー率54% (1660/3060)
http://ideone.com/72Wxp あってるか自信ない。
お礼
何度も丁寧かつわかりやすい回答、本当にありがとうございます。 何度も回答してもらっておきながら、まだ学校に行って確認が取れていません。申し訳ありません。しかし、自分で考えるに、やはり今回の問題は(1)のケースであると思っています。なので、頂きましたアドバイスを参考に問題解決を目指したいと思います。 本当にありがとうございました。