プロが教えるわが家の防犯対策術!

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

A 回答 (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 にする』
 ということですね。
・以上。おわり。

この回答への補足

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

補足日時:2007/02/02 14:07
    • good
    • 0

★解釈は質問者さんの考え方であっています。


・全く問題なく、正しい解釈ですよ。
・以上。おわり。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/02/04 19:02

訂正。



>「定義されただけで使われてない状態」です。
良く見たらprint_bitsの中で使われてましたね。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/02/04 19:03

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

補足日時:2007/02/02 14:35
    • good
    • 0

関数の流れはちゃんと見てないのでしらないけど


1U、0Uは符号なし整数型リテラルでしょ。
~はビット否定演算子で、~0Uは全ビット1の整数になる。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/02/04 19:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!