- ベストアンサー
Cの共用体を使ったローテートについて
- Cでローテート関数を作る下記の模範解答があり、動作も確認済みですが、どうしてそうなるのかイマイチ理解できません。
- 私の考えでは、(1)のときにビットの状態は 0000 0000 0000 0000、(2)により ch[0]にchの値が渡されるので 0000 0001 0000 0000、(3)で左に1シフトされると 0000 0010 0000 0000 となり、i=1のときch[0]が2、以後インクリメントごとに4,8,・・・,128まではわかります。その後、ビットからはみ出した1が最下位に戻ってくるところがよくわかりません。
- コメント行の「c[1]」はビット番号のことではなくてch[1]の間違いなのか?だとしてもif文のch[1]は0ではないか???と悩んでます。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
> コメント行の「c[1]」はビット番号のことではなくてch[1]の間違いなのか? そのとおりですね。 ch[1]の間違いです。 > だとしてもif文のch[1]は0ではないか???と悩んでます。 このプログラムはリトルエンディアン専用のようですね。 以下のコードを考えて見ましょう。 このコードを実行した直後、c[0]~c[3]にはどのような値が入っていると思いますか? union { unsigned long l; unsigned char c[4]; } data; data.l = 0x12345678; 実は、これはマシンによって異なります。 たとえば、intel系CPUなどはリトルエンディアンと言われる設計ルールを使っています。 このようなCPUでは値は以下のようになります。 (c[0] == 0x78) (c[1] == 0x56) (c[2] == 0x34) (c[3] == 0x12) それに対して、ビッグエンディアンという設計ルールを採用している68系CPUなどではまったく逆の結果になります。 (c[0] == 0x12) (c[1] == 0x34) (c[2] == 0x56) (c[3] == 0x78) 要は、若いアドレスを上位バイトと捉えるか、下位バイトと捉えるか、の解釈の違いがあるわけです。 では、intが4バイトのリトルエンディアンであると想定してプログラムの動きを追ってみましょう。 まず、1回目の(2)の処理は ch[0] に対して0x01を代入しています。 リトルエンディアンなので最下位バイトに値が入り、uの値は0x00000001となります。 途中は省略しますが、8回目の(2)の処理で、uの値は0x00000080となります。 その直後の(3)の処理で、uの値は0x00000100となります。 このとき、ch[1]の値をリトルエンディアンで考えてみてください。 0x01になっているはずですよね? このサンプルコードは、あくまで共用体のサンプルだからこのような組み方をしてあるようですが、エンディアンの影響を受けてしまうので、あまり好ましいコードではないですね。 普通は共用体ではなく、ビットマスクを利用するべきです。
その他の回答 (2)
- sakusaker7
- ベストアンサー率62% (800/1280)
ISOの規格的にはちょっとまずかったんじゃないかなあという 気がするのですがそれはおいといて。 ch[1] ch[0] 0000-0000 1000-0000 の状態からさらに左(MSB方向)へシフトすると 0000-0001 0000-0000 になります。 つまり、c[1]が0から1になります。 そうすると if (rot.ch[1]) ← この条件が真になりますので rot.ch[0] = rot.ch[0] | 1; これで ch[0]の最下位ビットを立てる。つまり シフトの結果 0000-0000 になったch[0]を 0000-0001 にしている。 というわけです。
お礼
回答ありがとうございます。 ch[1],ch[0]の順に並んでるんですね。納得しました。 「ISOの規格的にまずかった」について気になるのでもう少し調べてみます。
- php504
- ベストアンサー率42% (926/2160)
関数内の処理中に各変数を出力すればわかると思いますが ch[0]に1を代入した段階で u も 1になっているはずです 0000 0000 0000 0001 <-ch[1]->|<-ch[0]-> ということですね
お礼
回答ありがとうございます。 ch[1],ch[0]の順に並んでるんですね。納得しました。
お礼
おっしゃる通り、「若いアドレスを上位バイトと捉えるか、下位バイトと捉えるか、の解釈」が間違っていることによるものでした。納得です! リトル(ビッグ)エンディアンという言葉も初めてでしたので新たに知識を得ました。(お恥ずかしながら・・・) この本の共用体の説明図では、ch[0]ch[1]という並びになっているのですが、C言語は汎用性がある一方、CPUによって使い分けなければならないわけですね。 丁寧なご説明どうもありがとうございました。