• ベストアンサー

関数とビット列

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); }

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★まず『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 にする』  ということですね。 ・以上。おわり。

ki_c
質問者

補足

回答ありがとうございます。 『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と& されている。 という解釈でよいのでしょうか? 関数が苦手で根本的に考え方が違うのかもしれませんが 教えてください。よろしくお願いします。

その他の回答 (4)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.5

★解釈は質問者さんの考え方であっています。 ・全く問題なく、正しい解釈ですよ。 ・以上。おわり。

ki_c
質問者

お礼

度々の回答本当にありがとうございました。

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.4

訂正。 >「定義されただけで使われてない状態」です。 良く見たらprint_bitsの中で使われてましたね。

ki_c
質問者

お礼

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

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.3

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関数から呼ばれていないので「定義されただけで使われてない状態」です。

ki_c
質問者

補足

回答ありがとうございます。 「数値定数のサフィックス」を参照わかりました。 また、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)
回答No.1

関数の流れはちゃんと見てないのでしらないけど 1U、0Uは符号なし整数型リテラルでしょ。 ~はビット否定演算子で、~0Uは全ビット1の整数になる。

ki_c
質問者

お礼

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

関連するQ&A