- ベストアンサー
関数とビット列
C言語勉強中です。下記本から抜粋したものですが、 関数の流れや、1U、~0Uなどの意味がわかりません。 それぞれ関数の中でどのような処理をしているのでしょうか? scanfで正数入力し、print_bitsにnxを渡し、そこのxを1と&して 2進の0か1を表示させるのはなんとなく解るのですが、PCのCPUの ビット数を確認する為?の動きなどがわかりません。 どうか、解説していただける方、よろしくお願いします。 #include <stdio.h> int count_bits(unsigned x) { int count = 0; while (x) { if (x & 1U) { count++; } x >>= 1; } return (count); } int int_bits(void) { return (count_bits(~0U)); } void print_bits(unsigned x) { int i; for (i = int_bits() - 1; i >= 0; i--) { putchar(((x >> i) & 1U) ? '1' : '0'); } } int main(void) { unsigned nx; printf("非負の整数を入力してください:"); scanf("%u", &nx); print_bits(nx); putchar('\n'); return (0); }
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
★まず『1U』と『~0U』を説明します。 ・数値の後ろにある『U』は、符号なしを表します。 ・ですから、『1U』は符号なしの整数値(UINT型)の定数になります。 『~0U』も符号なしの整数値(UINT型)の定数ですが、『~0』としているので『0』という数値を 全ビット反転します。 ・つまり INT 型が 32 ビットの環境では、 『 0U』→『00000000000000000000000000000000』 『~0U』→『11111111111111111111111111111111』 となります。→16進で表現すると『0xFFFFFFFF』となります。 ・『~』はビット反転の演算子です。だから、『0』のすべてのビットを反転すると PC の CPU の ビット幅のすべてが『1』になるため、この数を数えればビット長が数えられます。このカウント を『int_bits』関数と『count_bits』関数が行っています。分かりますか? 最後に: ・『count_bits』関数は単純に整数値のビットが立っている数を数え、『int_bits』関数が、整数の 全ビットを『1』にした整数値(~0U)を『count_bits』関数に渡してビット数を数えさせているのです。 ・これで『int_bits』関数で現在のビット数を取得できるので、『print_bits』関数でそのビット長を 利用して、上位ビットから順番に 2 進数の『0』か『1』を画面へ出力できるのです。 ・ポイントは 『~0U が、全ビットを 1 にする』=『CPUのビット長をすべて 1 にする』 ということですね。 ・以上。おわり。
その他の回答 (4)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★解釈は質問者さんの考え方であっています。 ・全く問題なく、正しい解釈ですよ。 ・以上。おわり。
お礼
度々の回答本当にありがとうございました。
- chie65536
- ベストアンサー率41% (2512/6032)
訂正。 >「定義されただけで使われてない状態」です。 良く見たらprint_bitsの中で使われてましたね。
お礼
回答ありがとうございました。
- chie65536
- ベストアンサー率41% (2512/6032)
http://www.geocities.jp/ky_webid/c/019.html 「数値定数のサフィックス」を参照の事。 「0U」は「unsigned intの0」 「0」は「(符号付きの)intの0」 「~」は「補数演算子」。ビットの0を1に、1を0にする。 「~0U」は「unsigned intの0を全部ビット反転して、全部のビットを1にした物」となる。 count_bits関数は、渡された値が0じゃない(つまり、どこかのビットが1になっているのが最低でも1つある)間、最下位ビットが1かどうか調べ、1つ調べた後に全ビットを下にずらして行く、と言う手法で「1になってるビットが何個あるか?」を調べます。 「最下位ビットが1かどうか」は「1U」つまり「unsigned intの1」とandした値が非0かどうかで調べています。 「1つ調べた後に全ビットを下にずらして行く」は「x>>=1」で行っています。これは「x = x >> 1」と同じ意味です。 0010001001100010 と 0000000000000001 を and、0なので何もしない 0010001001100010 を1ビット下にずらし 0001000100110001 にする 0001000100110001 と 0000000000000001 を and、非0なのでcountを加算 0001000100110001 を1ビット下にずらし 0000100010011000 にする 0000100010011000 と 0000000000000001 を and、0なので何もしない 0000100010011000 を1ビット下にずらし 0000010001001100 にする 0000010001001100 と 0000000000000001 を and、0なので何もしない 0000010001001100 を1ビット下にずらし 0000001000100110 にする 以下、どこかのビットに「1」がある限り、繰り返し。 int_bits関数はcount_bits関数に~0Uを渡して、結果を返すだけです。 「~0U」をcount_bits関数に渡すと「unsigned intで全ビットが1になった数値を渡し、その数値の1になっているビットの数を数える」と言う事になります。 これは「unsigned intが何ビットなのか調べる」と同じ意味です。 なお、int_bits関数もcount_bits関数も、main関数から呼ばれていないので「定義されただけで使われてない状態」です。
補足
回答ありがとうございます。 「数値定数のサフィックス」を参照わかりました。 また、count_bits関数の中身をとても丁寧に教えてくださり ありがとうございます。 ただ関数の解釈に不安があるので、もう少し教えてください。 (他の方と重複補足になり申しわけありません) 皆さんの回答をヒントに自分なりにも考えてみたのですが、 まず、void print_bits(unsigned x)関数にある、 for (i = int_bits() - 1; i >= 0; i--) { でint int_bits(void)関数に行き、そこから、 int count_bits(unsigned x)のxに(~0U)つまり、 unsigned 11…11(unsignedのCPUのビット幅)を渡して 1の数をカウントする。 int count_bits(unsigned x)関数とint int_bits(void)関数 のreturn値は全く同じだが、 int count_bits(unsigned x)関数はcount数を数えるため、 int int_bits(void)関数はunsigned 11…11(unsignedのCPUのビット幅)を渡すために作られている。 最初にscanfで入力された整数は、void print_bits(unsigned x)関数 の中のxでしか使われておらず、int count_bits(unsigned x)関数と int int_bits(void)関数で求められたカウント数分、1と& されている。 という解釈でよいのでしょうか? 関数が苦手で根本的に考え方が違うのかもしれませんが 教えてください。よろしくお願いします。
- rinkun
- ベストアンサー率44% (706/1571)
関数の流れはちゃんと見てないのでしらないけど 1U、0Uは符号なし整数型リテラルでしょ。 ~はビット否定演算子で、~0Uは全ビット1の整数になる。
お礼
回答ありがとうございました。
補足
回答ありがとうございます。 『1U』と『~0U』を説明、とてもよくわかりました。 ありがとうございます。 ただ関数の解釈に不安があるので、もう少し教えてください。 (他の方と重複補足になり申しわけありません) 皆さんの回答をヒントに自分なりにも考えてみたのですが、 まず、void print_bits(unsigned x)関数にある、 for (i = int_bits() - 1; i >= 0; i--) { でint int_bits(void)関数に行き、そこから、 int count_bits(unsigned x)のxに(~0U)つまり、 unsigned 11…11(unsignedのCPUのビット幅)を渡して 1の数をカウントする。 int count_bits(unsigned x)関数とint int_bits(void)関数 のreturn値は全く同じだが、 int count_bits(unsigned x)関数はcount数を数えるため、 int int_bits(void)関数はunsigned 11…11(unsignedのCPUのビット幅)を渡すために作られている。 最初にscanfで入力された整数は、void print_bits(unsigned x)関数 の中のxでしか使われておらず、int count_bits(unsigned x)関数と int int_bits(void)関数で求められたカウント数分、1と& されている。 という解釈でよいのでしょうか? 関数が苦手で根本的に考え方が違うのかもしれませんが 教えてください。よろしくお願いします。