
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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# C言語 3 2022/11/09 13:27
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- C言語・C++・C# C言語 3 2022/10/04 15:07
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C++で表を作成したいのです ...
-
2の補数を計算するプログラム
-
C言語の問題
-
カードシャッフルのブログラム...
-
| (or) を使った関数の引数の作...
-
C++デバックエラーについて詳し...
-
画像の拡大・縮小
-
argvのNULLチェック
-
2次関数プログラムを描写する...
-
再起呼び出しの回数をカウント...
-
MFCでネガポジ変換
-
intとlongは同じ?
-
3のつく数と3の倍数を表示 C言語
-
低次元なコーディング方法について
-
OpenCVによる4値化について
-
whileとifを使い偶数を出すには
-
コマンドプロンプトのウィンド...
-
再帰処理をループ処理に変換
-
c++ TCHARで文字化け
-
異なるn個の整数からr個の整数...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
2の補数を計算するプログラム
-
intとlongは同じ?
-
条件が多い場合
-
再起呼び出しの回数をカウント...
-
argvのNULLチェック
-
C言語でDOS画面のプログラム(...
-
カードシャッフルのブログラム...
-
c++ TCHARで文字化け
-
複数の共有メモリの作成
-
C++ Debug Errorについて教えて
-
C++ bmp 透過処理
-
関数とビット列
-
OpenCVによる4値化について
-
コマンドプロンプトのウィンド...
-
ヌメロンのプログラム
-
for 分についてです
-
DXライブラリとC言語 fwrite関...
-
16bitで乱数を生成する方法
-
プログラミングに関して
-
C++で表を作成したいのです ...
おすすめ情報