• ベストアンサー

関数とビット列

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

  • ki_c
  • お礼率63% (28/44)

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

  • ベストアンサー
  • 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

  • ビット構成について

    今、ビットについて勉強しているのですが、わからないところがありますので、質問しました。わかる方がいれば、わかりやすく教えてください。(例として、整数xは10とした場合をしてもらえる助かります。) 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 count_bits(unsigned x){ int count = 0; while (x){ if (x & 1U) count++; x >>= 1; } return (count); } についてですが、整数Xを10とした場合、私の考えではcount=2となると思うのですが・・・。 次に int int_bits(void){ return (count_bits(~0U)); } についてなのですが、count_bits関数で整数Xを10とした場合count=2となったあと、int_bits関数では全ビットを1にするということみたいですが、count_bits関数でおこなった作業をどうint_bits関数で処理するのかわかりません。 最後が for文の中の、(i = int_bits() - 1 ; i >= 0; i--) についてですが、整数10のときの i = int_bits() はどうなっているのでしょうか?? わかりにくい質問ですみません。 回答宜しくお願いします。

  • unsigned型のビット構成を表示するプログラムが理解できません。

    unsigned型ビット構成の表示プログラム #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); } このプログラムで10を入力したら、00000000000000000000000000000001010と表示され。 18だと00000000000000000000000000000010010と表示される原理が理解できません。 自分なりにプログラムを追ってこういう考えてます。 まず、10を入力したらcount_bitsの関数の処理からスタート。 while(x){ if(x&1U)count++; x>>=1; if(x&1U)の処理を行い。x=10はbit単位表示で、1010として考え。一番右側の101「0」とunsigned型の1との論理比較を行う。0と1なので偽で何もせずにif文を抜けて、x>>=1;を行いx=0101となり。while(x)から再びif(x&1U)行う。x=0101の一番右側のunsigned型の1との論理比較を行い0と1なので真なのでcount++を行いcount=1としてif文を抜け、x>>=1;を行いX=0010になり。三度目のif(x&1U)の処理を行う。0010の一番左側のunsigned型の1との論理比較を行い0と1なので偽でif文を終了。x>>=1;を行い0001となり、再びif(x&1U)行う。 00 01の一番左側のunsigned型の1との論理比較を行い0と1なので真なのでcount++を行いcount=2となり、x>>=1;を行い0000なのでwhile(x)を抜けて返り値2をint_bitsへ返して関数は終了 int_bitsではunsinged型の2が戻り値としてprint_bitsへ返し、int_bitsの関数は終了。 print_bitsの処理が始まり。for(i=int_bits()-1;i>=0;i--)の処理がスタート。 i=int_bits()-1の処理でiは2-1でi=1からスタート。 putchar(((x>>i)&1U)?'1':'0');の処理。 (x>>i)でx=10,i=1なので1010>>1だから0101。 0101の一番右側の1とunsigned型の1と論理比較を行う 真なのでputcharは'1'を一度表示。 for文に戻りiをデクリメントとしてi=0なのi>=0から 一度、putchar(((x>>i)&1U)?'1':'0');処理。 (x>>i)は0101>>0の0右シフト行い0101。 unsignedと1を0101の一番右側の1と論理比較を行う 真なのでputcharは'1'を一度表示。 for文に戻りiをデクリメントとしてi=-1なのでi>=0からfor文を終了してprint_bitsの処理を終了。mainの関数処理に戻り。putchar('\n');を出力して関数処理は終了。表示として「11」が表示される。18も同様に考えているので、「11」が表示されてしまうのでは?という考えに陥ってます。実際は、両方とも正しくunsigned型ビット構成の表示されるので、自分の考え方が間違えている。なのですが、どう間違えているかがわかりません。 多少説明文の省略しているためわかりにくいかもしれませんが、間違えを指摘していただけないでしょうか?

  • c言語による2のべき乗

    右、左シフトと2のべき乗による乗除算が同じことを証明するプログラムを作っているのですがうまくいきません。 プログラムを載せるのでどこが間違っているのかご教授お願いします。 #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, no, n1, n2; printf("非負の整数を入力してください:"); scanf("%u", &nx); printf("何ビットシフトしますか?:"); scanf("%u", &no); n1=nx * (2^no); n2=nx / (2^no); printf("\n整数 = "); print_bits(nx); printf("\n左にシフトした値 = "); print_bits(nx << no); printf("\n右にシフトした値 = "); print_bits(nx >> no); printf("\n2のべき乗で乗算した値 = "); print_bits(n1); printf("\n2のべき乗で除算した値 = "); print_bits(n2); putchar('\n'); return(0); }

  • 困っています

    どうしても、--unsigned型のビット内容表示--の所が意味が分かりません。分かりやすく教えてください。宜しくお願いします。 /* 0~UINT_MAXを2進・8進・16進で表示 */ #include <stdio.h> #include <limits.h> /*--- 整数xのセットされたビット数を返す ---*/ int count_bits(unsigned x) { int count =0; while (x) { if (x & 1u) count++; x>>=1; } return (count); } /*---- unsigned型のビット数を返す ----*/ int int_bits(void) { return (count_bits(~0U)); } /*---- unsigned型のビットを内容を表示 ---*/ 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 i; for (i=0; i<UINT_MAX; i++) { print_bits(i); printf(" %6o %5u %4X\n", i, i, i); } return(0); }

  • C言語 unsigned 表示

    #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)); } unsigned rrotate(unsigned x1 ,int n){ int bits=int_bits(); n%=bits; return(n? (x1>>n)|(x1<<(bits-n)):x1); } int main (void){ unsigned nx,b; b=rrotate(nx,2); printf("%u\n",b); return(0); } 3221225476や1073741829と表示されることがあります。 入力値を4で割った数を表示するには、どうしたらよいでしょう・ 御指摘お願いします。

  • ビット操作について

    void print_bit(unsigned x) { for(int i=int_bit()-1;i>=0;i--) { putchar(((x>>i) & 1U)?'1':'0');      } } int main(void) { print_bit((~0>>16)); return0; } と入力したのですが、結果が 111111111111111111111111111111 と出てしまうのですが。 自分的には0000000000000000111111111111111と出したいのですが。 どうしたらいいのでしょうか? できるならどうしてこのような結果になったのか教えていただけたらな と思います。よろしくお願いします。

  • 素数 再帰関数

    メイン #include<stdio.h> extern void count_primes(void); extern void print_primes(void); int max; int count; int primes[1000] int main(void) { printf("Uper limit: "); scanf("%d",&max); count_primes(); print_primes(); } 素数を求める(関数呼び出し) extern int nextprime(int n); extern int max; extern int count; extern int primes[]; void count_primes(void) { int i; count=0; for(i=2;i<=max;i=nextprime(i)){ primes[count++]=i; } リカーバシブ(次の素数) int nextprime[int n] { int i; for(;;){ n++; for(i=2;i*i<=n;i=nextprime(i)){ if(n%i==0) break; } if(i*i>n) break; } return n; } 素数プリント #include<stdio.h> extern int count; extern int primes[]; void print_primes(void) { int i for(i=0;i<count;i++){ if((i>0)&&(i%10==0) printf("\n"); printf(" %6d",primes[i]); } printf("\n素数の数 %d\n",count); } これら4つのモジュールで素数 nが求められますがアルゴリズム理解できません。この2つの関数のアルゴリズムについて、ご教授ください。め

  • 直角三角形を表示するプログラム

    下記のプログラムを実行するとコマンドプロントになにも表示されず、強制終了しなければならなくなってしまいます。 whileのところがおかしいのはわかったのですが、この書き方の何がいけないのかが分かりません。 初歩的な質問で申し訳ありませんが、回答していただけると有難いです。 #include <stdio.h> int main(void){ int count, i; printf("何段ですか?"); scanf("%d", &count); for(i = 1; i <= count; i++){ while(i-- > 0){ putchar('*'); } putchar('\n'); } return 0; }

  • モンテカルロ法の面積近似

    Mが2の32乗の、線形合同法で乱数を発生し、 モンテカルロ法を使って、 領域a = {(x,y)|x≧1,y≧2,(x-1)^2 + (y-2)^2 ≦1}の面積の近似値を計算するプログラムを作成し、これを利用してn=10000とした場合の上の領域の面積、および円周率πの近似値を求めよ。 (関数を使う) という課題が出たのですが、乱数の出し方?が変であまり近似されません(^_^;) どなたかどこが変か教えてください(>_<) これだと、2と4になってしまうんです(/_;) #include<stdio.h> #include<stdlib.h> #include<math.h> #define N 100 /*領域Rを含む面積T 領域R=求める面積*/ #define Nx 1 #define Ny 2 /*乱数を発生させる関数*/ unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c); int main(){ unsigned long int x0, a, c, M; double x, y, s; int n, count_in, count_out; count_in = 0; count_out = 0; printf("x0: ", x0 ); scanf("%d", &x0); a = 61; c = 49; for(n = 0; n < 10000; n++){ /*乱数を発生*/ x = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Nx + 1; y = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Ny + 1; if(x >= 1 && y >= 1 && pow(x-1, 2) + pow(y-2, 2) <= 1) count_in++; else count_out++; } s = (double)count_in/(count_in + count_out)*Nx*Ny; printf("s = %f\n", s); printf("pi = %f\n", 2*s); return 0; } unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c){ int i; x0 = (a*x0 + c); /*printf("%u\n", x0);*/ return x0; }

  • C言語で分からないことがあります。

    私は初心者で、ある参考書で下記の例が載っていたのですが、このプログラムで分からないことがあります。 #include<stdio.h> void nchar(int ch,int no) { while(no-->0) putchar(ch); } int main(void) { int i,ln; printf("何段ですか:");scanf("%d",&ln); for(i=1;i<=ln;i++){ nchar(' ',ln-i); nchar('*',i); putchar('\n'); } return 0; } まず、 ・nchar関数のnoは何を表しているのか? ・nchar関数のputchar(ch)は一体何を表しているのか? 参考書にはこのプログラムについてあまり説明が無くこの2点がよく分かりません。 よろしくお願いします。