プロが教える店舗&オフィスのセキュリティ対策術

題名の通り配列を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 ]

ご教授お願いします。

A 回答 (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
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/01/09 22:27

★回答者 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) キャストを利用しています。
 これでも上手くいきます。多分こちらの方が分かりやすいかもしれない。
    • good
    • 0
この回答へのお礼

何度も丁寧に教えてくださってありがとうございます。
#4の回答を参考にして一応求める値が作れるようになりました。
本当に感謝しております。

ただmaskをつかわずに
『hi = (buf[i - 1] & mask) << (8 - 3);』⇒
『hi = (buf[i - 1]) << (8 - 3);』
でやっても結果は同じく正常になります。
これはこの処理では左にシフトしているため他のビットの値は何でもいいということでしょうか?
ここだけまだ少しもやもやしています。。。

お礼日時:2008/01/09 21:34

修正します。


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--;
 }
}
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/01/09 16:42

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]);
}
    • good
    • 0

★アドバイス


>ですと下位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);
 }
}
以上。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

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

よろしくお願いします。

お礼日時:2008/01/09 16:45

配列の数が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]);
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/01/09 16:48

配列の数、シフト数を汎用的に作るなら



#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);
}
    • good
    • 1
この回答へのお礼

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

お礼日時:2008/01/09 16:41

とりあえず、考え方だけ。



# まるまる答えを書いてしまうと、削除されてしまうかもしれませんので。。。

まず、ビットシフトは以下のようにすればできますよね。

========================================================
int hoge = 0x30;
int n = 3;

hoge >>= n; /* hoge == 0x06 */
/*------------------------------------
 hoge >>= n; は
 hoge = hoge >> n; と等価。
------------------------------------*/
========================================================

あとは、配列のインデックスで for でループをまわせばいけそうですけど、そういう話ではないのでしょうか?

この回答への補足

ご回答ありがとうございます。

>あとは、配列のインデックスで for でループをまわせばいけそうですけど、そういう話ではないのでしょうか?

for(i=0;i<3;i++){
buf[i] >>= n;
}
ですと下位3ビットがなくなりますよね?
この3ビットを次の配列に移動する方法がよく分からなくて・・。
素人質問ですみませんがよろしくお願いします。

補足日時:2008/01/09 02:14
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/01/09 16:43

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています