• ベストアンサー

配列をnビットシフトする

題名の通り配列をnビットシフトする方法を教えてください。 char buf[3] = { 0x30,0xf0,0x80 }というデータで n=3 だった場合 欲しいデータはbuf[3] = { 0x06,0x1e,0x10 }です。 { 0x30, 0xf0, 0x80 } →{ 0x06, 0x1e, 0x10 } [ 00110000,11110000,10000000 ]→[ 00000110,00011110,00010000 ] ご教授お願いします。

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.8

★追記。 >これはこの処理では左にシフトしているため他のビットの値は何でもいいということでしょうか?  ↑  左にシフトした後で (char) 型にキャストされるからです。  これは hi、lo 変数が char 型なので左シフトした9ビット以上が自動的にカットされるからです。  キャストを利用すると9ビット以上をカット出来るため 0xFF で AND を取るのと同じ効果があるのです。  同じ効果になるだけで『何でもいい』訳ではないのです。hi、lo が char 型以外だと 0xFF で  AND を取る必要があります。 ・以上。

参考URL:
http://www9.plala.or.jp/sgwr-t/c/sec14.html
dora40
質問者

お礼

納得いたしました。 ほんとうに何度もありがとうございました。

その他の回答 (7)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.7

★回答者 No.4 です。 ・ちょっとマスク値の演算方法が間違っていました。訂正。  間違い⇒『mask = (char)(~0 >> (8 - 3));』  正しい⇒『mask = (char)(0xFF >> (8 - 3));』  ※『~0』で11111111111111111111111111111111=0xFFFFが作れます。  ※でも今回は1バイトの 0xFF の定数にした方が良さそうです。 >mask = (char)(0xFF >> (8 - 3));  ↑  この mask には 0x07 がセットされます。  2進数では 00000111 です。  この 00000111 を作り出すためにの演算です。  ちなみに (8 - 3) の 3 がシフトする数です。 ・nビットのシフトの場合は次のようにします。  mask = (char)(0xFF >> (8 - nBit));  これは次のようになります。  (1)『0xFF』は11111111(2進数)となります。  (2)(8 - nBit) で nBit=3 ならば (8 - 3)=5 となります。  (3)この値11111111(2進数)を右に5ビットシフトします。   すると00000111(2進数)となり0x0007(16進数)です。  (4)あとは mask に 0x0007 が代入されます。 ・さて mask に 0x0007 が必要な理由ですが、これは『hi = (buf[i - 1] & mask) << (8 - 3);』で  使っています。この意味は分かりますか?  意味は右に3ビットシフトするため、配列の1つ前の下位3ビットを取り出すためのマスク値です。  前回は mask でビットANDを取っていますが、mask 値を使わずにキャストを使っても出来そうです。 サンプル: unsigned char buf[ MAX_BUFF ] = { 0x30, 0xF0, 0x80, …, 0x12 }; int i = MAX_BUFF; // 配列の後(うしろ)から処理 while ( --i > 0 ){  buf[ i ] = (unsigned char)((unsigned char)(buf[i - 1] << (8 - nBit)) | (buf[i] >> nBit)); } buf[ i ] = (unsigned char)(buf[i] >> nBit); ※今回は mask 値を使わずに (unsigned char) キャストを利用しています。  これでも上手くいきます。多分こちらの方が分かりやすいかもしれない。

dora40
質問者

お礼

何度も丁寧に教えてくださってありがとうございます。 #4の回答を参考にして一応求める値が作れるようになりました。 本当に感謝しております。 ただmaskをつかわずに 『hi = (buf[i - 1] & mask) << (8 - 3);』⇒ 『hi = (buf[i - 1]) << (8 - 3);』 でやっても結果は同じく正常になります。 これはこの処理では左にシフトしているため他のビットの値は何でもいいということでしょうか? ここだけまだ少しもやもやしています。。。

  • luckymako
  • ベストアンサー率55% (29/52)
回答No.6

修正します。 void shift(unsigned char src[], unsigned char dst[], int len, int bit){  int i = len - 1;  int j = bit / 8;  int b = bit % 8;    while(i > j){   dst[i] = src[i - j - 1] << (8 - b) | src[i - j] >> b;   i--;  }    if(i == j){   dst[i] = src[i - j] >> b;   i--;  }    while(i >= 0){   dst[i] = 0x00;   i--;  } }

dora40
質問者

お礼

ご回答ありがとうございます。 参考にさせていただきます。

  • luckymako
  • ベストアンサー率55% (29/52)
回答No.5

8ビット以上のシフト、結果の出力先指定ができます。 #include<stdio.h> void shift(unsigned char src[], unsigned char dst[], int len, int bit){  int i = len - 1;  int j = bit / 8;  int b = bit % 8;    while(i > j){   dst[i] = src[i - j - 1] << (8 - b) | src[i - j] >> b;   i--;  }    dst[i] = src[i - j] >> b;  i--;    while(i >= 0){   dst[i] = 0x00;   i--;  } } int main(){  int i;  int len = 3;  int bit = 3;  unsigned char src[] = {0x30, 0xf0, 0x80};  shift(src, src, len, bit);  for(i = 0; i < len; i++)   printf("%x\n", src[i]); }

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★アドバイス >ですと下位3ビットがなくなりますよね? >この3ビットを次の配列に移動する方法がよく分からなくて・・。  ↑  この場合は配列の後(うしろ)から処理します。  そして前の配列から下位3ビットをシフト演算します。 サンプル: char buf[ 3 ] = { 0x30, 0xf0, 0x80 }; char hi, lo; char mask; int i; // 右に3ビットシフトするためのマスク値 mask = (char)(~0 >> (8 - 3)); // 配列の後(うしろ)から処理 for ( i = 2 ; i >= 0 ; i-- ){  hi = (buf[i - 1] & mask) << (8 - 3);  lo = (buf[i - 0] >> 3);    if ( i != 0 ){   buf[ i ] = (hi | lo);  }  else{   buf[ i ] = (lo);  } } 以上。

dora40
質問者

お礼

ご回答ありがとうございます。 // 右に3ビットシフトするためのマスク値 mask = (char)(~0 >> (8 - 3)); ↑の行の意味がよくわかりません。 もしよろしければ簡単に説明していただけないでしょうか? よろしくお願いします。

  • nak777r
  • ベストアンサー率36% (49/136)
回答No.3

配列の数が3個で固定なら、long にセットしてビット シフトでもいいですね unsigned char buf[]={0x30,0xf0,0x80}; int n = 3; long tmp; printf( "%02x %02x %02x\n",buf[0],buf[1],buf[2]); tmp = buf[0]; tmp<<=8; tmp |= buf[1]; tmp<<=8; tmp |= buf[2]; tmp>>=n; buf[2] = tmp & 0xff; tmp >>=8; buf[1] = tmp & 0xff; tmp >>=8; buf[0] = tmp; printf( "%02x %02x %02x\n",buf[0],buf[1],buf[2]);

dora40
質問者

お礼

説明不足ですみません。配列の数は可変です。 なのでこの方法は難しそうですね。 ご回答ありがとうございました。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

配列の数、シフト数を汎用的に作るなら #define COUNT 3 #define INDEX 3 int main(void){ int i, j, bit, tmp; unsigned char buf[INDEX] = { 0x30,0xf1,0x80 }; for (i = 0; i < COUNT; i++) { bit = 0; for (j = 0; j < INDEX; j++) { tmp = buf[j] & 1; /* 最下位ビットを保存 */ buf[j] >>= 1; /* 1ビットシフト */ buf[j] |= bit; /* キャリービットを追加 */ bit = tmp << 7; /* キャリービットを更新 */ } } return(0); }

dora40
質問者

お礼

ご回答ありがとうございます。 参考にさせていただきます。

  • ency
  • ベストアンサー率39% (93/238)
回答No.1

とりあえず、考え方だけ。 # まるまる答えを書いてしまうと、削除されてしまうかもしれませんので。。。 まず、ビットシフトは以下のようにすればできますよね。 ======================================================== int hoge = 0x30; int n = 3; hoge >>= n; /* hoge == 0x06 */ /*------------------------------------  hoge >>= n; は  hoge = hoge >> n; と等価。 ------------------------------------*/ ======================================================== あとは、配列のインデックスで for でループをまわせばいけそうですけど、そういう話ではないのでしょうか?

dora40
質問者

お礼

ご回答ありがとうございます。 参考にさせていただきます。

dora40
質問者

補足

ご回答ありがとうございます。 >あとは、配列のインデックスで for でループをまわせばいけそうですけど、そういう話ではないのでしょうか? for(i=0;i<3;i++){ buf[i] >>= n; } ですと下位3ビットがなくなりますよね? この3ビットを次の配列に移動する方法がよく分からなくて・・。 素人質問ですみませんがよろしくお願いします。

関連するQ&A

  • 配列の配列をmemcpyやmemcmpしたいです

    【環境】WindowsXP(SP2)、VisualStudio2005++(MFC) タイトルの通りなんですが、配列の配列を比較したりコピーしたいのですが、以下に質問を3つ記載させていただきますので、どなたかご教授お願いいたしますm(__)m 1.宣言と初期化について char **buf; buf = new char*[3200]; for(int i=0; i < 3200; i++) { buf[i] = new char[4]; } これで、buf[1]、buf[2]、buf[3]、buf[4]に、それぞれ3200のchar型の配列が宣言された事になりますでしょうか? ※buf[4][3200] なのか buf[3200][4]なのかよく分からないです。 2.上記の方法で定義した2つの配列(bufとtmp)の比較 for(int i =0; i < 4; i++) { memcmp (buf[i], tmp[i], sizeof(tmp[i])); } これで比較出来ますでしょうか? 3.上記の方法で定義した2つの配列(bufとtmp)のコピー for(int i =0; i < 4; i++) { memcpy_s(buf[i], sizeof(buf[i]), tmp[i], 3200 * sizeof(char)); } これではバッファオーバーランエラーが発生してしまうのですが、どこがおかしいでしょうか? 以上3点、初心者の質問なので意味が分からないような箇所があるとは思いますが、どうかご教授お願いいたしますm(__)m  

  • 1ビットごとの配列を作りたい

    例えばchar型で 5 0 4 という3つの数値があった時、 1 00000101  0  1 00000100 という配列にしたいのですが (5と4の前の1は「次は8ビット読む」という印。空白は見やすくするための物) ネットで調べてもよく分かりませんでした。 教えていただきたいのは、 ・ある構造体、配列などから上記のようなビット配列にする方法 ・ビット配列から通常の値にする方法 ・ビット配列のサイズ取得方法 です よろしくお願いします

  • 2バイトデータのビットシフトについて

    PIC 12F683 をつかった温度ロガーのプログラムについて、 質問させていただきます。 こちら http://www8.plala.or.jp/InHisTime/page179.html#PIC-144 のプログラムなのですが、mikroC のソース、 http://www8.plala.or.jp/InHisTime/PIC-144/thermo_logger_v3.c の、EEPROMからのデータ読み出し部分で、 EEPROM_24LC1025_Page_Read(addr, buf, 2); ad = (buf[1] << 8) + buf[0]; このように、読み出したデータ(buf)に対して、 ビットシフトをしているのですが、 このようにして、データが取り出せることの、仕組みがわかりません。 たとえば、AD変換のデータが、デフォルトの左詰め10ビットとして、 buf[1] : 1111 1111 buf[0] : 1100 0000 というデータだとして、上記のビットシフトで、 なぜデータが取り出せるのかが理解できません。 どなたか、よろしければなるべく具体的に、 お教え願えませんでしょうか。

  • ビット演算について

    いつもお世話になります。 ビット演算について教えて下さい。 unsigned char buf1[1]=0x5a unsigned char buf1[2]=0x04 unsigned char buf1[3]=0x38 5a0438(16)を3バイトの値を12ビットずつの整数で得るにはどうしたらいいのでしょうか? 2進数表記では、 5A | 04 | 38 01011010 | 00000100 | 00111000 12ビットずつとは、 010110100000 010000111000 と区分し、10進数の整数値で得たいです。どのようにすればよいでしょうか? また、0x5Aなどの16進数を2進数のビットで考えるときに、 01011010を下位4ビットを10進数整数を得るにはどうしたらよいのでしょうか? 上記2点、どうぞよろしくお願い致します。

  • C言語の配列の扱い

    次のような配列bufと変数dataを宣言して bufの中身をdataにコピーしたいのですが、 buf[0]のみで、buf[1]の値が入りません。 具体的には、buf[0]には16進数で0x3f、 buf[1]には0x3aが入っていて、 dataの値を0x3a3fにしたいのです。 教えてください。 ***************************** unsigned char buf[2]; unsigned short data; data = (unsigned short)*buf; *****************************

  • マスク処理・ビットシフト教えてくださいっ!

    10文字入る文字型配列aaを、ビットの列と考える(全部で80ビット)、この配列のビットを先頭から0ビット目、1ビット目、・・、79ビット目と数えると、 0ビット目:aa[0]の0ビット 7ビット目:aa[0]の7ビット 9ビット目:aa[1]の1ビット 17ビット目:aa[2]の1ビット では、nビット目は「aa[S]のRビット」とした時、SとRをビット操作でnを用いてどのように求めればよいか今までの課題と同様に答えなさい。 マスク処理する場合には、AND 0x00F0のように書き、ビットシフトする場合にはシフトするビット数をnからどのようなビット処理で求めるかを書くこと。 この問題が分からなくて困っています…! 教えてくれる方いらっしゃいませんか?

  • double型の値をchar配列に変換する方法はありますか?

    double型の値をchar配列に変換する方法はありますか? 例えばdoubleの1.0をcharの配列に{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F}のように

  • javaのbyte配列へintなどを埋め込む方法

    javaのbyte配列へintなどを埋め込む方法 java初心者です。データ編集がわからなくて悩んでいます。 下記のコードは"棒読みちゃん"といソフトへのTCPパケットを作成するコードです。 char buf[15]; *((short*)&buf[0]) = 0x0001; *((short*)&buf[2]) = speed; *((short*)&buf[4]) = tone; *((short*)&buf[6]) = volume; *((short*)&buf[8]) = voice; *((char* )&buf[10]) = 2; *((long* )&buf[11]) = len; 同じことをJAVAでしたいのですがわかりません。 (バイト型配列へint,long型を簡単に埋め込む方法がわかりません) よろしくお願いします。 よかったら、こちらもお願いします memcpy(&buf[15],message,strlen(messege)); TCPパケットのようなデータ処理が頻繁にある場合、 このようなコードは、どうしたらいいでしょうか? *((unsigned char* )&buf[15]) = message; CとJAVAになってますが、このような処理を簡単に書けないでしょうか?

    • ベストアンサー
    • Java
  • 配列から構造体へデータコピー

    配列から構造体へデータのコピーをしたいのですが、 構造体のメンバがビットフィールドで構成されている時の処理がわかりません。 --------test.c----------- #include <stdio.h> #include <string.h> typedef struct{ unsigned char aaa :1; unsigned char bbb :1; unsigned char ccc :1; unsigned int ddd :13; unsigned char eee :2; unsigned char fff :2; unsigned char ggg :4; }test_t; int main(void) { test_t test_t; unsigned char data[]={0x5F, 0xFE, 0x1C}; memcpy(&test_t, data, 4); printf("aaa = %X\n", test_t.aaa); printf("bbb = %X\n", test_t.bbb); printf("ccc = %X\n", test_t.ccc); printf("ddd = %d\n", test_t.ddd); printf("eee = %X\n", test_t.eee); printf("fff = %X\n", test_t.fff); printf("ggg = %X\n", test_t.ggg); return 0; } ------期待出力--------- aaa = 0 bbb = 1 ccc = 0 ddd = 1FFE eee = 0 fff = 1 ggg = 12 「test.c」を実行した時に「期待出力」のような出力を期待していたのですが、実際には aaa = 1 bbb = 1 ccc = 1 ddd = 1 eee = 0 fff = 0 ggg = 0 と表示されてしまいます。 ビットフィールドで構成された構造体に、配列の値をそのままあてる事は出来ないのでしょうか? 出来るだけ、マスクやシフト演算を使用しないで、配列からビット単位で値を抽出したいのですが・・・

  • C言語のビットシフトの質問

    C言語の右ビットシフトで、以下のプログラムの結果について、納得できずにいます。 dを右にシフトすると、上位ビットには0が入るのではないでしょうか? よろしくお願いします。 プログラム unsigned char d='0'; printf("%c\n", d); printf("%c\n", d>>5); 結果 0 『

専門家に質問してみよう