Version 6.09
単項演算子
「さて今回から、バグの出やすい部分や見つけ方とかを具体的に紹介してい
きます」
『バグの出やすいとこってあるんだ』
「あるよー。まずは演算子関係」
『演算子って、 + とか - とかだよね』
「そうそう。そういう四則演算から、 << とかのビット演算系、 && とかの
論理演算系、 == や < の比較演算系、って感じに演算子はいっぱいありま
す」
『 MSDN で見てみても、かなりの数あるね』
「そこで、演算子関係のバグを紹介する前に、全部の演算子についてまとめ
ておきます」
『おお! って、もしかしてあたし、全然演算子のこと教えてもらってな
い?』
「必要になってから教えてたからね……。ま、今からでも遅くないでしょ」
『ホントかなー』
「さて、まず重要なのは、演算子は基本型に使うものってこと」
『基本型?』
「 int とか char とか、あとポインタとかの、最初から存在する型のこと
を〈基本型〉とか〈プリミティブ型〉とかいいます」
『つまりクラスじゃない型ってこと?』
「そういうこと! 基本的に、クラスには演算子を使えません」
void CDebugDlg::OnButton1()
{
CWnd cWnd;
cWnd = 100;
}
『あ、コンパイルエラーになった』
「ただ、クラスの中には演算子を使えるようにしてあるものもあります」
void CDebugDlg::OnButton1()
{
CString cStr;
cStr = "あいうえお";
}
『ちょっとややこしいかも』
「 MFC のクラスなら、 MSDN で CString のメンバ関数を見てみると、
operator = とかあるでしょ。これが〈 = 演算子は使えるよ〉って意味」
『でもまだ難しい……』
「ま、今回はクラスの話じゃないからこれは置いといて。では早速、演算子
について見ていきましょう。 MSDN の【 C++ 演算子】ってページを開いて」
『あ、さっき見つけたページだ。いっぱいあるよねー』
「まー数はあるけど、実際はそんなに多いって感じないと思うよ。まず、使
い方別に見ていくね。 MSDN の【単項演算子】−【 C++ 単項演算子】を選
んで」
『ほい。 ! とか & とか出てきた』
「全部並べると、 ! & ~ * + - ++ -- 」
『最初の ! は if の中で使うのだね。反対にするヤツ』
「そう、 ! はゼロを 0 以外に、 0 以外をゼロにします」
『 & は……あれ? これって、アドレス出すの? それともビットで両方
とも 1 だったら 1 になるっての?』
「これは、アドレスの方の。ここに出てる演算子って〈単項演算子〉って
なってるでしょ。単項演算子っていうのは……〈オペランド〉って憶えて
る?」
『もちろん。 2 + 3 なら、 2 が左オペランドで、 3 が右オペランドで
しょ』
「こういう、左右にオペランドがくっつくのを【二項演算子】っていいま
す。オペランドの事を〈項〉って言うからね。ってことは?」
『単項演算子は、オペランドがいっこってこと?』
「そういうこと! だから、 & 変数が1個だけ付いてたら単項演算子、2
個付いてたら二項演算子として機能するわけ」
『二項か単項かって、どう見分けるの? あ! 二項は変数にくっつけない
で、単項はくっつけるんだ!』
「ぶっぶー。単項演算子は変数と離してても機能します」
void CDebugDlg::OnButton1()
{
int i = 0;
TRACE( "%X\n", & i );
}
『これでアドレスがちゃんと出るんだ……』
「それに、二項演算子で変数とくっつけないのは僕のスタイル。くっつけて
る人は結構いるよ?」
『そういえば……』
「単項演算子か二項演算子かっていうのは、演算子掛けたあとは値になる、
ってことを憶えとけば大丈夫だと思うよ」
『値になる、って、たとえばさっきの ! だと 0 とか 0 以外になるとかっ
て意味?』
「そうそう、 & ならアドレスになるし、 ++ なら1増えた値だし。これは
二項演算子にも言えることでしょ」
『そういえば、 a + b はその足したのに置き換わる、って前にやったね』
「 Ver 2.4 ( No.015 ) だね。かなり昔……」
『この〈置き換わる〉って、 typedef とかに似てるね』
「それは結構重要なこと」
『おお』
「でも難しいから、詳しくはもう少し先になってから」
『あら』
「話を元に戻すと、さっきの火美ちゃんの例に似た形で言えば」
a & b
「は、もし & を単項演算子にしちゃうと」
『 & b が値に置き換わっちゃう』
「変数や値が、演算子ナシに並ぶのはダメだからこれはあり得ない、だから
コンパイルするときに & は二項演算子だ、って扱われるわけ」
『でもさ、これは?』
a & &b
「単項演算子は右側の変数にしかくっつかないからね。真ん中の & は a に
付かないでしょ」
『単項演算子は右側の変数にしか付かない、ね』
「あ、後置の ++ と -- は別だからね」
『次の行に行く前に増えたり減ったりってヤツね。そういえばあれは変数の
右側に付けるよね』
「ま、あれは特別。単項演算子は右にくっつく、って憶えとけばOK」
『ようするに、矛盾がなければそう見られるってことでしょ?』
「まぁね。単項演算子で分かんないのある?」
『 ~ は教えてもらってないかな。 MSDN 見ると〈1の補数〉って書いてあ
るけど、何それ。歩数1? 1歩前へ?』
「補数っていうのは、普通の10進数の数で言うと、足して9とか99とか
にする数字。7を9にするには?」
『2足せば9』
「ってことは7の補数は2てこと。こういう〈補う数〉を〈補数〉って言う
わけ。簡単に言えばね」
『その補数を作るのが ~ ってことなんだ……あれ?』
TRACE( "%d\n", ~7 ); // -8
『ウソツキ!! なにが足して9になる数よ!!』
「違う違う! ~ は10進数じゃなくて、2進数での補数を作る演算子な
の!」
『2進数?』
「そう。 0x77777777 を例にしてみようか。10進数の9、つまり〈次の桁
に移る直前の数〉は、16進数だと?」
『15。ってことは、7引くと8だね』
「ってことで」
TRACE( "%X\n", ~0x77777777 );
// 88888888
『お、ホントだ』
「でしょう」
『……んな勝ち誇った顔はいいから、これが何の役に立つの?』
「そこが重要。とりあえず、今言った〈補う数〉とかっていうのは忘れてい
いから」
『えええ??』
「16進数の 7 をビットで表すと?」
『 0111 だよ』
「じゃあ 8 は?」
『 1000 ……って、水希ちゃんバカにしてる?』
「同じく、 5 について」
TRACE( "%X\n", ~0x55555555 );
// AAAAAAAA
『 5 は 0101 、 A は 1010 だよ』
「さて問題。ビットで表すと、普通の数と補数の関係は?」
『えーっと……あ!』
「そう、ビットが反転してるでしょ」
『なに? つまりようするに ~ はビット反転するための演算子ってこ
と?』
「そういうこと。補数とか難しいこといってるけど、基本的にはこれだけの
こと」
『じゃー初めからそういえばいいじゃん。うー』
「まーそうなんだけどね」
『で、これって何に使うの?』
「一番よく使うのは、ビットフラグを取り除くときかな。 Ver 5.24
( No.089 ) でやったウィンドウスタイルの話を思い出して」
『ウィンドウの形とかが、ビットフラグで入ってるんだよね。
CWnd::GetStyle() とか使って調べられて』
「セットされてるスタイルから、あるひとつのスタイルだけ取り除く場合、
まずウィンドウスタイルを取得して、取り除くスタイルのビットを取り除い
て、再びセットしなおします」
『それに ~ を使うの?』
「そゆこと。たとえば 0101 から 0001 ビットを取り除きたい場合」
int iModified
= 0x00000005 & ~0x00000001;
TRACE( "%X\n", iModified );
// 4
『なんかややこしい……と、ひとつずつ見てけ?』
「そゆこと」
『 0x00000001 が 0001 、これを反転するから 1110 。で、 0101 と & す
るわけだから…… & って各ビットで、両方とも 1 のときだけ 1 だよね』
「そ。 4.05 ( No.055 ) を読み返してみて」
『だから、 0101 & 1110 で……ホントだ、 0100 で 0001 が取り除けた』
「 ~ で反転すれば、 0001 が 1110 になったみたく、立ってたビットだけ
が 0 に、他は 1 でしょ」
『当たり前じゃない』
「それに & すれば、立ってたビットは絶対に 0 になるから」
『そっか、それで絶対に消せるんだ』
「他のビットは、 1 のとこはそのまま 1 、 0 もそのまま 0 」
『ほー、良くできてるね〜。これが ~ の使い道ってわけだ』
「ってゆーか、実際にはこっちから見ていった方が分かりやすいかな」
『どゆこと?』
「つまり、まず〈ビットフラグを取り除く〉って目的から入って、それには
~ を使う、ってこと」
『それが〈必要になったら教える〉ってことね』
「プログラミングに使うものって、色々使えそうで、実はほんの少しのこと
にしか使われてないことって多いからね」
『あと単項演算子で知らないのは…… + と - は?』
「まんま、プラスとマイナス。正の数と負の数を作るためのもの」
『じゃ、単項演算子は全部分かったかな』
「では次回は二項演算子について見ていきましょう!」
/*
Preview Next Story!
*/
『ねー、単項演算子の + って何に使うの?』
「特に使い道ないんじゃないかな、たぶん」
『たぶん?』
「う”、演算子って実はこういう使い方ができる、とかあるからねぇ」
『水希ちゃんでも知らないことってあるのねー』
「というわけで次回」
< Version 6.10 二項演算子 >
『につづく!』
「でも、やっぱり使い道はないんじゃないかな」
『ホント?』
「う”……」