
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);
}
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 にする』
ということですね。
・以上。おわり。
この回答への補足
回答ありがとうございます。
『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と&
されている。
という解釈でよいのでしょうか?
関数が苦手で根本的に考え方が違うのかもしれませんが
教えてください。よろしくお願いします。
No.4
- 回答日時:
訂正。
>「定義されただけで使われてない状態」です。
良く見たらprint_bitsの中で使われてましたね。
No.3
- 回答日時:
「数値定数のサフィックス」を参照の事。
「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と&
されている。
という解釈でよいのでしょうか?
関数が苦手で根本的に考え方が違うのかもしれませんが
教えてください。よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
コマンドプロンプトのウィンド...
-
C言語で%を使わない余りの出し方
-
3のつく数と3の倍数を表示 C言語
-
C言語でDOS画面のプログラム(...
-
OpenCVによる4値化について
-
関数とビット列
-
分数の足し算をさせるプログラ...
-
「Aに対するBの割合」と「Aに対...
-
ある商品のロス率を5%見込み、...
-
Aの値からBの値を除するとは??
-
2曲同時再生するにはどうした...
-
DWORDの実際の型は何でしょうか
-
有効数字について 以前質問をし...
-
複数桁10進数の*桁目だけを抽出...
-
エクセルの問題です。絶対値の...
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
信頼区間の1.96や1.65ってどこ...
-
Enterキーを押されたら次の処理...
-
ネットワークにつながっている...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語で%を使わない余りの出し方
-
カードシャッフルのブログラム...
-
2の補数を計算するプログラム
-
OpenCVによる4値化について
-
ヒストグラム均等化処理プログラム
-
【C#】SQL文の中に変数を埋め込...
-
再起呼び出しの回数をカウント...
-
intとlongは同じ?
-
C++で表を作成したいのです ...
-
画像の拡大・縮小
-
argvのNULLチェック
-
c言語プログラミングについて f...
-
ヌメロンのプログラム
-
C言語でDOS画面のプログラム(...
-
OpenGLの惑星プログラム
-
opencvとmbedのシリアル通信で...
-
C言語プログラミング 漸化式に...
-
3のつく数と3の倍数を表示 C言語
-
猫でもわかるゲームプログラミ...
-
条件が多い場合
おすすめ情報