• ベストアンサー

変数の扱える範囲

C言語で、整数型変数の扱える範囲を確認するために 以下のような処理をしているのですが、どうもうまくいきません。 変数に入りうる最大値の値を、2進数の計算ではなく プログラム内で正しく扱われているか確認する方法はないでしょうか? ご存知の方、教えてください<(_ _)> 宜しくお願いいたします。 **********************************************  unsigned long long I; unsigned long A; unsigned int B; unsigned short C; printf("I:%d A:%d byte B:%d byte C:%d byte \n"    ,sizeof(I),sizeof(A),sizeof(B),sizeof(C)); A = B = C = 0; for(I = 0; I <= 4294967295; I++){ A++;B++;C++; if(I>= 4294967290 && I<= 4294967295)    printf("I:%d A:%d B:%d C:%d\n",I,A,B,C); }

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

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

#2の回答にもあるように、<limits.h>で定義されたマクロを使うのが標準的な方法です。 unsigned shortの最大値はUSHRT_MAX、unsigned intの最大値はUINT_MAX、unsigned longの最大値はULONG_MAX、unsigned long longの最大値はULLONG_MAXを使います。

peroncho
質問者

お礼

回答ありがとうございました。 試してみたいと思います。<(_ _)>

その他の回答 (7)

  • TT414
  • ベストアンサー率18% (72/384)
回答No.8

>printf("I:%d A:%d B:%d C:%d\n",I,A,B,C); はprintf("I:%lld A:%d B:%d C:%d\n",I,A,B,C); にしないとだめです。 A,B,Cは%dを%uに変えたほうが良いですが。 Iに関しては%lld又は%lluでないと、A,B,Cを正しく表示できません。 long longの出力は%lld又は%llu又は%llxです。 私の回答は質問に書かれたプログラムに関してです。 40億回もループさせないNo.2からNo.7の方の方法が良いですが。

peroncho
質問者

お礼

まとめのご意見ありがとうございました。 独学なので、皆さんにとって当たり前のことでも 知らないことが多いことを痛感しました! 大変助かりました。ありがとうございます!<(_ _)>

  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.7

すんません。C99(のドラフトですが)を確認したところ、unsigned typeの値は2^nのmoduloであることが保証されるようでした。とほほ・・・

peroncho
質問者

お礼

御回答ありがとうございました。 いまひとつ理解が追いついておりませんが、 取り急ぎお礼まで

  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.6

言語仕様まで確認していないのですが、「++u」がゼロになるまで回してその直前の値を最大値とするのであれば、それは「u = 0; --u;」で得られる結果と同じになりませんか? これならビット演算はいらないので2の補数表現ではない処理系でも実行でき、ループも必要ありません。 もっとも、オーバーフロー・アンダーフロー発生時の式の値や変数の値は、それが合理的な値かどうかも含めて「処理系依存」と定義されている(=無茶苦茶な値になっても文句は言えない)ような気がしますが。

  • jagd-doga
  • ベストアンサー率31% (14/45)
回答No.5

> コンパイル時にforループのIをインクリメントするところで > 次のような警告が出るのですがループがうまく回らないようです。 > “warning: decimal constant is so large that it is unsigned” これは、インクリメントでwarningが出ているのではないと思います。 ループ条件に対して言っているのだと思います。 4294967295 以下というループ条件ですが、decimalに直すと、0xffffffff (つまり -1)で、 unsigned longの変数Iと比較すると、常にループ条件は偽になりますよ、だから、コンパイラが最適化して、unsignedと解釈します。と言っているのだと思います。(適当ですけど) for(I = 0; I <= (unsigned long)4294967275; I++) としてみてください。 warning 出なくなります。 たぶんですけど。 あと、私見ですが、 整数型変数の扱える範囲を確認するため というのであれば、#2の方の方法が最もスマートだと思います。 処理系に依存しますが、64bitマシンでプログラミングした際、unsigned longの最大値が0xffffffffffffffffだったことがあります。 #2の方のプログラムでしたら、どんな場合でも最大値が出力されます。 #1の方のプログラムでは、ループ条件に4294967295が使われていますので、4294967295が最大か、そうでないかしかわかりません。

peroncho
質問者

お礼

ありがとうございます。 参考にさせていただきます<(_ _)>

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.4

#1です。 >ABに関しては以下のようになってしまいます。 >A=-1 >B=-1 符号無し整数は%uを使用します。%dは符号付き整数です。 printf("I:%d A:%d B:%d C:%d\n",I,A,B,C); を printf("I:%d A:%lu B:%u C:%d\n",I,A,B,C); としてください。

peroncho
質問者

お礼

再度御回答いただきましてありがとうございます。 printfも十分に理解しておりませんでした。 よくわかりました。(^^ゞ

回答No.2

「正しく」という意味がよく分からないのですが(特にunsigned 系だと、最大値と最小値は紙一重です)、最大値は下記の方法で入らないでしょうか?(ビット演算だけどね) unsigned long ul; ul = 0; ul = ~ul; 処理系によっては結果は変わるかもしれませんし、いま手元にコンパイラがないので確認できませんが。 ただ、今調べていて limits.h というヘッダにはその処理系の最大値・最小値が定義されていることを思い出しました。 ここで定義されている定義済み定数を使えば、処理系の差から来るトラブルを最小にしながらプログラムをかけます。 http://www9.plala.or.jp/sgwr-t/c/sec13.html また、printf() での出力指示子もなかなか奥の深いものがありますので研究してみてください。

参考URL:
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/printf.3.html
peroncho
質問者

お礼

御回答ありがとうございます。URLもありがとうございました。 なるほど、いろいろあるんですね♪すばらしい。 勉強不足でさらっと理解できそうにないので、 おいおい勉強していきたいと思います。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.1

>変数に入りうる最大値の値を、2進数の計算ではなく >プログラム内で正しく扱われているか確認する方法はない>でしょうか? この意味が不明ですが、要はA,B,Cがとりうる最大の値をプログラムで確認したいということでしょうか。 unsigned long A,A1; unsigned int B,B1; unsigned short C,C1; として for(I = 0; I <= 4294967295; I++){ A1=A; B1=B; C1=C; A++;B++;C++; if (A==0)の時 A1が最大値なのでこれを印字 if (B==0)の時 B1が最大値なのでこれを印字 if (C==0)の時 C1が最大値なのでこれを印字 } ではいかがでしょうか。 符号無し整数の最大値に1を加えると0に戻る性質を利用しています。

peroncho
質問者

補足

さっそくご回答ありがとうございます。 処理してみますと、unsigned shortのCは正しく出力されるのですが ABに関しては以下のようになってしまいます。 A=-1 B=-1 C=65535 コンパイル時にforループのIをインクリメントするところで 次のような警告が出るのですがループがうまく回らないようです。 “warning: decimal constant is so large that it is unsigned”

関連するQ&A

  • 沢山の変数を扱う時、うまく出来ません・・。

    変数が沢山ある時、エラーが起こったかどうかは どうやって判断したらいいんでしょうか。 今50個位変数名があるとします。 今は端おって5つにします。 int a,b,d; char c,e a = (int *) calloc(500,sizeof(int)); b = (int *) calloc(200,sizeof(int)); c = (char *)calloc(700,sizeof(char)); d = (int *) calloc(400,sizeof(int)); e = (char *)calloc(100,sizeof(char)); if(a==NULL || b==NULL || c==NULL || d==NULL || e==NULL)   printf("エラー発生\n"); こうやって50個もif文の中にいれたら大変ですよね。 変数名も長いですし。うまく1つでもエラーが起きたら全体がエラーになるように出来ませんかね? 自分としてはこういう風に考えたんですけど int sum=1; a = (int *) calloc(500,sizeof(int)); sum*=a; b = (int *) calloc(200,sizeof(int)); sum*=b; c = (char *)calloc(700,sizeof(char)); sum*=c; d = (int *) calloc(400,sizeof(int)); sum*=d; e = (char *)calloc(100,sizeof(char)); sum*=e; if(sum==0)   printf("エラー発生\n"); コレくらいしかないですかね?

  • ポインタのsizeofについて

    C初心者です。 ポインタ宣言させた変数をsizeof()で値を取得させて 表示させてみました。 char *cp; short int *sp; int *ip; i = sizeof(cp); printf("%d\n",i); i = sizeof(sp); printf("%d\n",i); i = sizeof(ip); printf("%d\n",i); 結果は全て4となりました。 これはなぜですか? (ただの変数として宣言すれば1、2、4となります。この理由も理解できています。)

  • (Mac) sizeof演算子のコンパイル

    現在MacBookAirにて入門書を参考にC言語を学んでいます。 その中で、 #include <stdio.h> int main(void) { int a = 1; printf("short int型のサイズは%dバイトです。\n", sizeof(short int)); printf("変数aのサイズは%dバイトです。\n", sizeof(a)); return 0; } と入力しコンパイルすると sample21.c:7: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’ sample21.c:8: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’ と表示されコンパイルすることができません。 なんども見直してコードに間違いはないと思いますが、原因が解りません。 他のコードは問題なくコンパイルできます。 この先、sizeof演算子を使って値を求めなければならない章があり、非常に困っています。 どなたか解決策を教えてください。お願いします。

  • GlobalAllocの変数を関数に引き渡したい

    あるプログラムでGlobalAllocで指定バイト数を割り当てた変数を別の関数に引き渡したいのですが、やりかたが分からず困っております。 手元にある本はGlobalAllocについてすら書いておらず… 以下のようなプログラムになります。 ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー int math( int a, int b, unsigned short c ){ // 関数中身の演算に意味はない unsigned short sum; for( int i=a; i<b; i++ ) sum += c[i]; return sum; } int main(){ int Depth = 6; int sum; unsigned short *mem = GlobalAlloc( GPTR, Depth*sizeof(unsigned short) ); sum = math( 1, 3, mem ); // これな風にmemを値を引数として渡したい return 0; } ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー お分かりになる方がおられましたら、ご回答いただけると幸いです。 宜しくお願い致します。

  • 最近のCPUのほとんどはリトルエンディアンかビッグエンディアンでしょうか?

    2000年あたり以降に出た Windows, Mac, Linuxに使われているCPUのほとんどはリトルエンディアンかビッグエンディアンでしょうか? また、たとえば以下のような方法でエンディアンを調べられると考えていいのでしょうか?(VC++です) #include <windows.h> void GetEndian4(char* c){ unsigned __int32 a=0x03020100; BYTE *b = (BYTE*)&a, i=4; while (i--) c[i]=b[i]; } ////////// const char e[4]={}; GetEndian4( const_cast<char*>(e) ); //eが 0,1,2,3 になればリトルエンディアン //3,2,1,0 になればビッグエンディアン //PDP-エンディアンだと 2,3,0,1 …のはず (または2択ならこれだけでも判断可能…?) short s=1; printf( *(char*)&s ? "リトルエディアン\n" : "ビッグエディアン\n" ); あとここでもアラインメントの問題が絡みますが、このように アラインメントが(2のべき乗だとして)大きいであろう方から小さいであろう方にキャストする分には安全で、逆に sizeof(short) == sizeof(char)*2 として char c[2]={1,0}; short s=*(short*)&c; というのは危険な場合がある、ということでしょうか? また、その場合は たとえばビッグエンディアンなら short s=(c[0]<<8)|c[1]; とすればいいでしょうか?

  • C言語に直して下さい

    VisualC++で円周率を求めるプログラムなのだそうですが、 自分はC言語しか使ったことがないため、よく分かりません。 Cでコンパイルできるように直していただけないでしょうか。 よろしくお願いします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 21 #define K 100000 void add(unsigned long a[],unsigned long b[]) { int c = 0, tmp; for (int i = N - 1; i > -1; i--) { tmp = a[i] + b[i] + c; a[i] = tmp % K; c = tmp / K; } } void sub(unsigned long a[],unsigned long b[]) { int c = 0, x = 0; for (int i = N - 1; i > -1 ; i--) { x = c; if (a[i] < b[i] + x ) c = 1; else c = 0; a[i] = c * K + a[i] - b[i] - x; } } void div(unsigned long a[], unsigned long x) { int c=0, tmp; if (x >= K) { printf("Div Error\n"); getchar(); exit(1); return; } for (int i = 0; i < N ; i++) { tmp = (a[i] + c * K) / x; c = (a[i] + c * K) % x; a[i] = tmp; } } void clear(unsigned long a[]) { memset(a,0x00,sizeof(a)*N); } void set(unsigned long a[], unsigned long b[]) { memcpy(a,b,sizeof(a)*N); } void set(unsigned long a[], unsigned long b) { if (b<K) { clear(a); a[0]=b; } } int _tmain(int argc, _TCHAR* argv[]) { unsigned long pai[N], fn[N], gn[N], tmp1[N], tmp2[N]; int i; unsigned long n; clear(pai); clear(fn); clear(gn); clear(tmp1); clear(tmp2); set(fn, 16*5); set(gn, 4*239); for(n=0;n<40000;n++) { div(fn, 25); div(gn, 239); div(gn, 239); set(tmp1, fn); div(tmp1, 2*n+1); set(tmp2, gn); div(tmp2, 2*n+1); if (n%2==0) { add(pai, tmp1); sub(pai, tmp2); }else{ add(pai, tmp2); sub(pai, tmp1); } } for (i=0;i<N;i++) { printf("%5lu ", pai[i]); } getchar(); return 0; }

  • int型の変数値をバイト列としてコピー

    あるint型の変数に格納されている情報を、バイト列としてコピーする方法で困っています。 変数の入っている領域をそのままコピーしたいので、memcpyを使うかと思うですが、 コピーされた結果を見ると文字列の並びが逆転しているように見えます。 --サンプルコード抜粋 unsigned int i= 12345; unsigned char *c; c = (char *)malloc(sizeof(int)); printf("i_hex=%x\n",i); memcpy(c,(int *)&i,sizeof(int)); 出力結果 i_hex=3039 cの出力結果 3930000000 単純にmemcpyではダメなのでしょうか? 実行環境は、CentOS(32bit)+gccです。よろしくお願いします。

  • char型変数のアドレスを coutで表示するには

    #include <iostream> using namespace std; int main() { bool b; int i; short s; long l; float f; double d; char c; //上で宣言した変数のアドレスを表示 cout << "bool &b " << &b << endl; cout << "int &i " << &i << endl; cout << "short &s " << &s << endl; cout << "long &l " << &l << endl; cout << "float &f " << &f << endl; cout << "double &d " << &d << endl; cout << "char &c " << &c << endl; //「char &c 」とのみ表示される cout << '\n'; //char型のみ printf で再表示 printf("char &c %p\n", &c); //「char &c ********」と表示される return 0; } 上のプログラムを実行すると cout << "char &c " << &c << endl; のところだけ、アドレスが表示されません。 printfを使えば、char型の変数のアドレスも表示されるのですが…。 coutを使ってchar型のアドレスを表示させるにはどうすればいいのでしょうか。 よろしくお願いします。

  • MicroC コンパイラ 変数宣言

    MicroC コンパイラ 変数宣言について質問です BYTE tmp1; WORD tmp2; なる定義があったとして 変数型範囲はどの範囲になるのでしょう 下記の定義は見つかったのですが 上記は分かりません 変数型 バイト数 範囲 (unsigned) char 1 0 .. 255 signed char 1 - 128 .. 127 (signed) short (int) 1 - 128 .. 127 unsigned short (int) 1 0 .. 255 (signed) int 2 -32768 .. 32767 unsigned (int) 2 0 .. 65535 (signed) long (int) 4 -2147483648 .. 2147483647 unsigned long (int) 4 0 .. 4294967295 float 4 ±1.17549435082 * 10-38 .. ±6.80564774407 * 1038 double 4 ±1.17549435082 * 10-38 .. ±6.80564774407 * 1038 long double 4 ±1.17549435082 * 10-38 .. ±6.80564774407 * 1038

  • char型+char型ってint型? if(char型==int型)?

    C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。 char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。 (下のプログラムの printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */ という部分の結果は4なので、int型と考えるべきなのかな。) 私は、char型とint型の加算の結果はint型だと思っていましたが、 char型とchar型の加算の結果はやはりchar型だと思っていました。 (それが間違えているのでしょうか。) if(a[0]==i) /* char型とint型の比較(?) */ の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。 (私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。) 左辺はchar型のように見えて、じつはint型ですか。 #include <stdio.h> int main(void) { char a[4]; int i=77; printf("sizeof(int)は%d\n", sizeof(int)); printf("sizeof(char)は%d\n", sizeof(char)); printf("sizeof('M')は%d\n", sizeof('M')); printf("sizeof(a[0])は%d\n", sizeof(a[0])); a[0]='M'; a[1]=7+6; a[2]=a[0]+a[1]; printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */ printf("sizeof(+a[0])=%d\n", sizeof(+a[0])); if(a[0]==i) /* char型とint型の比較(?) */ puts("a[0]==i"); else puts("a[0]!=i"); return(0); } ちなみにワーニングもエラーもなんにもでません。

専門家に質問してみよう