• ベストアンサー

配列を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