サイトマップ / C言語講座>出入り口>総目次>目次:バグ対策>整数の取り得る範囲
[整数の内部表現]←このソース→[NDEBUGマクロとassert( )]
/* 今日は、printf( ) で整数を表示する際に、変数が書式指定子の範囲を超えていたら、どうなるかについて実験します。
整数の取り得る範囲については、limits.h の中で記号定数を使って、次のように記述されています。
CHAR_BIT 8 // char 型は8ビット CHAR_MAX UCHAR_MAX // char 型とunsigned char 型の最大値は同じ CHAR_MIN 0 // char 型の最小値 INT_MAX +32767 // int 型の最大値 INT_MIN -32768 // int 型の最小値 LONG_MAX +2147483647L // long 型の最大値 LONG_MIN -2147483648L // long 型の最小値 SCHAR_MAX +127 // signed char 型の最大値 SCHAR_MIN -128 // signed char 型の最小値 SHRT_MAX +32767 // short 型の最大値 SHRT_MIN -32768 // short 型の最小値 UCHAR_MAX 255U // unsigned char 型の最大値 UINT_MAX 65535U // unsigned int 型の最大値 ULONG_MAX 4294967295UL // unsigned long 型の最大値 USHRT_MAX 65535U // unsigned short 型の最大値 // unsigned : 符号なし // signed : 符号あり
上に示したのはあくまでも1例で、処理系によって値が異なる可能性があります。
重要:特定の数字をソースコードに書き込んではいけません。
int x = INT_MAX; などと、記号定数を使って記述して下さい。その際、limits.h をインクルードして置くのを忘れないで下さい。
今回は、幾つかの型の最大値を表示し、次いで、同じ書式指定子を使って、それを1越える値を表示することを試みます。結果は、異常な値を表示します。また、最小値を表示し、次いで、それより1小さい数を表示することも試みます。
ソースプログラムを見て下さい。2組の printf( ) が並んでいます。上側の文は、かなり複雑な形をしていて、一見しただけでは、何が表示されるかわかりません。まずは、コンパイルして、実行して見ましょう。
ソース: printf("%d\n", SCHAR_MIN ); 結 果: -128 (OK!) ソース: printf("%d\n", SCHAR_MAX); 結 果: 127 (OK!) ソース: printf("%d\n", SHRT_MIN); 結 果: -32768 (OK!) ソース: printf("%d\n", SHRT_MIN -1); 結 果: 32767 (Bug!) ソース: printf("%d\n", SHRT_MAX); 結 果: 32767 (OK!) ソース: printf("%d\n", SHRT_MAX +1); 結 果: -32768 (Bug!) ソース: printf("%ld\n", LONG_MIN); 結 果: -2147483648 (OK!) ソース: printf("%ld\n", LONG_MIN -1); 結 果: 2147483647 (Bug!) ソース: printf("%ld\n", LONG_MAX); 結 果: 2147483647 (OK!) ソース: printf("%ld\n", LONG_MAX + 1); 結 果: -2147483648 (Bug!)
上記の文が画面に表示されるはずです。これは、あくまでも一つの例で、処理系によっては、値が変わってきます。
2組の printf( ) 文は、上の方が、Cのソースコードを表示させるもので、下の方がその結果をあらわしたものです。
ソースコード中のコメントにも書きましたが、'%' を表示させるには '%%' と記述するので、'%%d' で '%d' と表示されます。
'\' を表示させるには '\\' と記述するので、'\\n' で \n と表示されます。
ダブルコーテイション( " )を表示するには、'\"' と記述します。このような手はずで、ソースコードを画面に表示しています。
#include <stdio.h> #include <limits.h> void main(void); void main(void) {
こういった文も全て fprintf( ) で、ファイルに出力するプログラムを作れば、そのプログラムの実行結果をもう一度コンパイルして、実行できます (^^)。 */
#include <stdio.h> #include <limits.h> /* 文字定数を使う */ void main(void); void main(void) { /* \" : " と表示される %%d : %d と表示される \\n : \n と表示される */ printf("ソース: printf(\"%%d\\n\", SCHAR_MIN );\n"); printf("結 果: %d (OK!)\n", SCHAR_MIN); printf("ソース: printf(\"%%d\\n\", SCHAR_MAX);\n"); printf("結 果: %d (OK!)\n", SCHAR_MAX); printf("ソース: printf(\"%%d\\n\", SHRT_MIN);\n"); printf("結 果: %d (OK!)\n", SHRT_MIN); printf("ソース: printf(\"%%d\\n\", SHRT_MIN -1);\n"); printf("結 果: %d (Bug!)\n", SHRT_MIN -1); printf("ソース: printf(\"%%d\\n\", SHRT_MAX);\n"); printf("結 果: %d (OK!)\n", SHRT_MAX); printf("ソース: printf(\"%%d\\n\", SHRT_MAX +1);\n"); printf("結 果: %d (Bug!)\n", SHRT_MAX +1); printf("ソース: printf(\"%%ld\\n\", LONG_MIN);\n"); printf("結 果: %ld (OK!)\n", LONG_MIN); printf("ソース: printf(\"%%ld\\n\", LONG_MIN -1);\n"); printf("結 果: %ld (Bug!)\n", LONG_MIN -1); printf("ソース: printf(\"%%ld\\n\", LONG_MAX);\n"); printf("結 果: %ld (OK!)\n", LONG_MAX); printf("ソース: printf(\"%%ld\\n\", LONG_MAX + 1);\n"); printf("結 果: %ld (Bug!)\n", LONG_MAX + 1); } |
/* 処理系によっては、最小値より、1 小さい値を正常に表示するものもあります。
printf("%d\n", CHAR_MIN -1); printf("%d\n", CHAR_MAX + 1);
上記のコードは正常に動作します。書式指定子 %d で表示できる範囲は、INT_MIN から INT_MAX の間 ( -32768 から +32767 の範囲 )だからです。
変数は、その値の取り得る範囲を熟考してから、型を決めなければなりません。一例を下記に示します。
c = getchar( );
c には文字が入るので、c は char 型かというと、getchar( ) は入力に失敗すると、EOF ( -1 ) を返すので、int 型でなければなりません。 */
[整数の内部表現]←このソース→[NDEBUGマクロとassert( )]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−