• ベストアンサー

ビット演算を学びたい

a &= 2; a |= 2; a ^= 2; a ~= 2; a <<=2; a >>=2; みたいな感じでビット演算が使われているソースを 良く見るのですが、いまいちビット演算で何をしているのかが 分かりません。 参考書などには文字通りビットをいじるような旨のことが書いてあります。 (こちらにも同じようなことが http://www9.plala.or.jp/sgwr-t/c/sec14.html) こういうので何となくは分かるのですが、 実際にこれを何に使えるか、実践ではどのように使うのかが なかなか見えてきません。 このビット演算を私のような者でも実際のプログラムで使いこなせるように なれるようなサイトや書籍の提示、あるいはサンプルのプログラムなどで ご指導いただけたらと思います。

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

  • ベストアンサー
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

>実際にこれを何に使えるか、実践ではどのように使うのかが >なかなか見えてきません。 実際に、ビット演算が必要な状況はあまり発生しません。従って、なかなか、見えてこないのは、当然のことです。 ビット演算が必要な状況の例として、メモリのサイズを節約する場合に必要となることがあります。 では、どのような場合に、メモリを節約するかというと、 ファームウェアの場合のように、メモリの絶対量が少ない場合等があります。通常のパソコンでは、あまり、メモリの節約を意識せずにプログラミングができるので、このようなケースはあまりありません。 強いて例をあげれば、データが大量にあるとき、例えば100万件のデータがあるとき、1つのデータのサイズを小さくすると、非常に大きな効果が得られる場合があります。 もし、1つのデータが、100バイトの場合、100万件なら、10000万バイトになります。これが、半分ですむなら、5000万バイトになり、5000万バイトのメモリの節約となります。 では、どうやって、1つのデータを半分にするか(半分にはならなくても出来るだけちいさくするか)ですが、基本的には、その情報が、格納できるだけの、ビットに、縮めてしまう方法をとります。 例えばint型(4バイト)のデータは約10桁の数値が格納出来ますが、このデータのとりうる値が4桁までしか発生しないことが、明白であればshort型でとります。これにより4バイトが2バイトになります。これは、ビット演算を必要としません。 では、以下の場合は、どうでしょうか。 3種類のデータがあり、1つは性別(0:男、1:女)を表し、 もう1つは、血液型(0から3の数値があれば良い、A,B,AB,O) もう1つは、体重(0~31迄しかないとします。例ですので、それじゃ足りないというつっこみはしないで下さい) そうすると、メモリの節約をする必要がない場合は、全てinit型で確保するので4×3は12バイトになります。多少、節約の努力をすると、全てchar型でも良いので1バイト×3=3バイトになります。 これを更に、節約すると、性別:1ビット、血液型:2ビット、体重:5ビットですみます。これは、合計8ビットですので、char型(1バイト)で済みます。 そうすると、このデータが100万件ある場合は、非常に有効な節約になります。 では、性別 char sei; 血液型 char blood;体重 char weight;が与えられたとき、これを1つのchar型データ char data;にまとめるサンプルです。sei=0~1,blood=0~3,weight=0~31の数値です。 dataの左側の1ビットに、性別、次の2ビットに血液型、最後の5ビットに体重を格納します。 sei = sei << 7; blood = blood << 5; data = sei | blood | weight; 次がchar dataが与えられたときに、これを 3つの性別、血液型、体重に分解する例です。 sei = (data >> 7) & 0x01; blood = (data >> 5) & 0x03; weight = data & 0x1f;

amazontester
質問者

お礼

かなり具体的な例を挙げてくださりありがとうございます。 結構イメージが分かってきた気がします。

その他の回答 (4)

  • caceres
  • ベストアンサー率43% (61/140)
回答No.5

No1です。 No3の方の書かれたことをよくというか必ず使います。 マイコンの場合は使用メモリ量を気にしながらになりますから データ範囲が数ビット分で済む場合など、構造体として定義するとint定義で複数のメンバーを定義出来ます。 もっとも構造体を利用すればNo3の方のようなビット処理は不要です。が場合によっては高速処理になるので共用体定義にしてbit処理を利用します。 マイコンでロボット制御など1クロックでも無駄にしたくない場合はアセンブラコードを見てクロック数計算が必要になる場合もあります。 PICの無償開発ツールMplab ideと無償Cコンパイラを使って変数をWatchしながらデバッガでステップ実行するとよく分かりますよ。 以下の例ではdsPICで2サイクル構造体処理の方が早かったですがdsPICはC言語に適合する構成のためでしょう。通常はbit処理の方が早かったりわかりやすい処理も多いと思います。 //構造体 struct zData{     unsigned  sex  :1;  //性別   [0 or 1] (0=男,1=女) ****|****|****|***0     unsigned  blood:2; //血液型 [0--3](A,B,AB,O)        ****|****|****|*00*     unsigned  rh :1;   //RH     [0 or 1] (+/-)    ****|****|****|0***     unsigned  weight:10;//0~512kg Kg単位(小錦サイズも含む)   **00|0000|0000|****     unsigned  dmy:2; //16bit中 余った分 }; //共用体 union uData{  int  iDB;  struct zData zDB; }; union uData rDat; //データ格納 2byte rDat.zDB.sex=1; //女 rDat.zDB.blood=2; //AB rDat.zDB.rh=1; //RH+ rDat.zDB.weight=75; /75kg //同様にbitで書き込む場合の記述は rDat.iDB =0; rDat.iDB |=1; rDat.iDB |=(2<<1); rDat.iDB |=(1<<3); rDat.iDB |=(75<<4);

amazontester
質問者

お礼

これは確かビットフィールドとかいう手法ですね。 (独習Cで読んだ覚えが) ビットの図までつけて頂いた様で、この例もとても勉強になりました。

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.4

http://oshiete1.goo.ne.jp/qa2041537.html 演算子「 | 」について http://oshiete1.goo.ne.jp/qa2274746.html ビットシフトってどんな時使うの?

amazontester
質問者

お礼

リンク先を拝見いたしました。 とても勉強になりました。ありがとうございます。

  • herbest
  • ベストアンサー率42% (15/35)
回答No.2

メール送受信で利用されるBASE64エンコーダ/デコーダなどで使ったりします。 それほど難しくもないので実際に作って見てはどうでしょう。勉強になりますよ。 他には暗号などでもよく(ほぼ?)使います。 確かに使わないときはあんまり使わないんですよね。 勉強したいなら、例えばunsigned int型の変数を2進数で表示する関数なんか作って見てはどうでしょう。 ほんの数行の関数ですがしっかり理解してないと難しいかもしれません。

参考URL:
http://dolphin.c.u-tokyo.ac.jp/~naka7/base64.html
amazontester
質問者

お礼

なるほど。。暗号化ですか。 2進数で表示する関数をちょっと調べてみましたが、 簡単そうでなかなか複雑で勉強になりました。 ありがとうございます。

  • caceres
  • ベストアンサー率43% (61/140)
回答No.1

何に使うかはプログラムの設計をするうちに必要なことが分かってくるでしょう。 例えば シフト  4倍にするのに4を掛ければよいですがかけ算が出来ないCPUもあります。 左シフトを2回 a = a<<2; すればX4と同じです。 マイコンでロボットなどを制御する場合、乗算処理とシフト処理では 処理時間が数倍~数十倍以上違いますから乗算など使えない場合もあります。 例えば and ビット C言語ではIntのビット幅が8,16,32とCPUとコンパイラによって変わります。例えばボタンが複数あるゲームコントローラを処理する場合ですが、このようなCPUに対する入力は通常,8bit単位で処理できるものが一般的です。 つまりあるボタンひとつが1bitに相当するのでONを判定するために if(A & 1)==0{}else{} でbit0のON/OFF状態が分かります。 同様にbit1の発光ダイオード(LED)を点灯させるために B=B | 0x02; とすると **** **1* になり状態を変えることが出来ます。 コンピュータの根の深い部分の操作になると、ハードウェア処理に関する部分なので必ずビット処理が多くなります。

amazontester
質問者

お礼

実際のプロの方のようでとても参考になりました。 ゲームのコントローラーの処理などには確かに使ってそうですね。

関連するQ&A

  • C言語の&に関する質問

    C言語で if (x == 0.0) (いろいろな計算) return x < 0.0 && (n & 1) ? -ans : ans; というプログラムがあるのですが、 最後のreturnのところで x がゼロ以下で且つ、n &1の場合には -ansを返し、そうでない場合にはansを返すとあるのですが、 n&1というのはどういう意味なのでしょうか? C言語で&と言えば、 http://www9.plala.or.jp/sgwr-t/c/sec14.html のページにあるように、ビットごとの AND演算子ですが、 この場合にはどういう意味で使われているのでしょうか?

  • ビット演算を理解するための参考書を探してます

    ビット演算を理解するための参考書を探してます。 基本情報技術者の午後問題のC言語において、次のリンク先の問題のようにビットを使ったプログラム問題がさっぱり分かりません。 http://www.rs.kagu.tus.ac.jp/infoserv/j-siken/H10a2/pm07.html そこで、今までビット演算系の問題に触れていなかったためだと思い、 ビット演算のプログラムを扱った詳しい参考書を探しています。 基礎から上記URLの問題レベルまでの内容のものが特に良いです。 回答よろしくお願いします。

  • ? : の使い方

    ?と:の使い方がわかりません。 http://www9.plala.or.jp/sgwr-t/c/sec14.html#s14-3 この辺を見てみると、1つだけ「?」が書いてある文なら理解できたのですが、複数あるとどうなるのかよくわかりません。 たとえば・・ int a=2,b; b = (a==1) ? (a==2) ? 11 : 12 : 13; こんな時です。 どのとき、どこの値が入るのでしょうか。 よろしくお願いします。

  • 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 というデータだとして、上記のビットシフトで、 なぜデータが取り出せるのかが理解できません。 どなたか、よろしければなるべく具体的に、 お教え願えませんでしょうか。

  • リスト構造

    1→2→3のようにポインタでリスト構造を作るとき、最後の3は何もさしていないのですが、初期化もせずNULLも代入しない状態で使っても問題無いのでしょうか? プログラムはちゃんと動くようですが。 このコードがそれにあたると思うのですが。 http://www9.plala.or.jp/sgwr-t/c/A/rei15-5.html

  • ビット演算について

    以下のプログラムを作成して、int型、char型、long型のAND演算・OR演算の結果の違いを見ました。 実行結果からchar型だけ結果の表示の仕方が他と異なっています。 一般的に、バイト数では、 char(1バイト) < short(2バイト) < int(4バイト) のはずなのに、出力結果は、 char(0xffffffff) > short(0xff) = int(0xff) となっていて、charが一番大きく?、shortとintが同じ結果? のようにみえてしまいよくわかりません。 私は、ビット演算が苦手なので、根本的に考え方が間違っているのかも しれませんが、どうしてこのような出力結果となるのか教えてください。 プログラム #include <stdio.h> #include <stdlib.h> int main() { int xi = 0x7F, yi=0x80; int stri1 = xi&yi; int stri2 = xi|yi; printf("** int **\n"); printf("%p\n",stri1); printf("%p\n\n",stri2); char xc = 0x7F, yc=0x80; char strc1 = xc&yc; char strc2 = xc|yc; printf("** char **\n"); printf("%p\n",strc1); printf("%p\n\n",strc2); short xl = 0x7F, yl=0x80; short strl1 = xl&yl; short strl2 = xl|yl; printf("** short **\n"); printf("%p\n",strl1); printf("%p\n\n",strl2); return(0); } 出力結果 ** int ** 0x0 0xff ** char ** 0x0 0xffffffff ** short ** 0x0 0xff

  • サンプルプログラムにあったビット和の意図

    あるサンプルプログラムで出てきた記述なのですが aaa =bbb | 0; ccc = ((ccc * 1000) | 0) * 0.001; ここで使用されている「|」の意図がわかりません。 「|」自体がビット和の演算子であることは理解しています。 ですが「| 0」とした場合、値は何も変わらないのではないでしょうか? 何か特別な意図があるのでしょうか?

  • シフト演算を用いた変換

    シフト演算を用いて、データを変換したいのです。 例えば、「00 01 0B 0A」となっているデータを、「0A 0B 01 00」となるようにシフト演算を用いて、変換したいのです。 0Aで1byteとなっていて、1byteごとにデータを格納して入れ替えるなど、方法は考えてみたのですが、実際のプログラムがさっぱり思いつきません。 ヒントだけでもいいので、教えていただけると嬉しいです。 すみませんが、よろしくお願いします。

  • 数学演算のサンプルコード集のあるサイトを探しています(VB6)

    VB6で数学演算のソースコードのサンプル集を探しています。 例えば今回は3次元のベクトルをX,Y,Z軸周りに任意の角度だけ回転する行列をプログラムしたいので、アフィン変換のサンプルなんかないかと探しています。いいサイトがあれば教えていただけませんでしょうか。 よろしくお願いします。

  • 論理演算

    ビットの判定するために次のコードをしました。 if ( A And 2 = 2 ) or ( A And 4 = 4 ) Then ~ Aの論理積の結果が2か4ならばThen以下の処理の中に入っていってもらいたいのです。 ところが上記のコードでは演算式になってしまっているようで、 結果的にAが0以外ならば全てThenに入ってしまうザルコードになってしまいました。 散々つつきまわって以下のように( ) で括ればいいことが分かりました。 if (( A And 2 ) = 2 ) or (( A And 4 ) = 4 ) Then ~ ( )で括ればいいというのは分かりましたが、理由はさっぱり分かりません。 一番最初に書いたコードでも正常に見えるからです。 納得がいきませんので、どなたか説明よろしくお願い致します。

専門家に質問してみよう