• ベストアンサー

LONG_MINを使って、正常値かどうか確かめたい。

こんにちは。30代の男性です。 C言語で、コマンドラインオプションから入力された2つの数字がlong型の範囲外であれば「正常値ではない。」と表示され、適正値なら加算が行われるプログラムを作っています。LONG_MINやLONG_MAXは正常値の範囲外の値かと思っていましたが、それぞれlong型の最小値と最大値なのですね。 -2147483648を入力しても正常に計算が行われ、-2147483649が入力されるとエラーが出されるようにするにはどのようにしたらよいでしょうか? よろしくお願いいたします。

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★自作関数でチェックする場合を紹介します。 ・最初に ASCII コードの環境のみです。→この環境に限定。 サンプル: int MyCheckAndStrtol( long *ret, const char *string ) {  unsigned long z;  unsigned long n;  int sign = +1; ←符号がない場合は『+』    while ( isspace(*string) ){ ←空白文字はカット   string++;  }  if ( *string == '+' ){   sign *= +1; string++;  }  else if ( *string == '-' ){   sign *= -1; string++;  }  else{   return( -1 ); ←符号以外の文字エラー  }  for ( n = 0L ; isdigit(*string) ; string++ ){   z = n;   n *= 10L;   n += (*string - '0'); ←文字を数値に変換      if ( (n / 10L) != z ){ ←オーバーフロー時のチェック    return( 0 );   }  }  if ( *string != '\0' ){ ←この処理はなくても良いかも。チェックの仕様により自由です。   return( -1 ); ←文字列の最後が \0 以外ならばエラーとする。カットしてもOK。  }  *ret = (long)(sign * n);  return( +1 ); ←範囲内。 } 最後に: ・サンプル『MyCheckAndStrtol』関数の引数は、  第1引数は文字列を整数に変換した値をセットします。→long型へのポインタ  第2引数はチェックする文字列です。→コマンドラインの引数などを渡す ・戻り値は、  0以上は long 型の範囲内。→正常値。  0ならば long 型の範囲外。→異常値。  0以下は、整数文字列としては記述がおかしいエラー。→『abc』などの文字 ・以上。おわり。→細かくチェックするには文字列を解析するしかないかもね。

参考URL:
http://libc.blog47.fc2.com/blog-entry-76.html
DT50
質問者

お礼

Oh-Orange様 わざわざサンプルコードをお送り頂き、ありがとうございます。問題は解決でました。ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (4)

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

既に回答が出ているように、strtolを使えばエラー検出が可能です(これが、atoiやatolを使うべきではない理由でもあります)。 簡単に例を挙げると、 #include <stdlib.h> #include <errno.h> int main(int argc, char *argv[]) {  char *endptr;  long value;  errno = 0;  value = strtol(argv[1], &endptr, 0);  if (errno != 0 || *endptr != '\0')  {   /* エラー処理 */  }   ...  return 0; } といった感じです。 ここで、strtolの第3引数(基数)を0にしているのは、0で始まれば8進数、0xまたは0Xで始まれば16進数として解釈できるようにするためです。 なお、long long型が使える処理系でも、-2147483648と比較するのはお勧めできません。移植性のこともありますが、long型が32ビットの場合、-2147483648はunsigned long型になってしまうため、long long型に型変換しても負の値にならないためです。C99であれば、-2147483648はlong long型になるので問題ありません。

DT50
質問者

お礼

ご回答頂きありがとうございます。 アドバイスも参考にさせて頂きます。ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • venzou
  • ベストアンサー率71% (311/435)
回答No.3

こんな感じで、調べられます。 #include <stdio.h> #include <stdlib.h> #include <limits.h> void main(int argc, char *argv[]) { int i; char *e; long n;  for(i = 1; i < argc; i++){   n = strtol(argv[i], &e, 10);   if(errno != ERANGE){    if (*e == '\0'){     printf("%02d : 値 = %ld\n", i, n);    }else{     printf("%02d : 値 = %ld 変換不能部分(%s)\n", i, n, e);    }   }else if (n == LONG_MAX){    printf("%02d : 大きすぎ (%s)\n", i, argv[i]);   }else if (n == LONG_MIN){    printf("%02d : 小さすぎ (%s)\n", i, argv[i]);   }  } } (注:見やすいように全角スペースが入っています、コンパイルする時は消してください。)

DT50
質問者

お礼

ご回答ありがとうございました。 Unixでコンパイルしましたが、エラーが出ました(^-^;。全角は削除したのですけどね。でも、もう解決できたので大丈夫です。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.2

コマンドラインで入力したものをチェックするということですので、 文字列→数値(long)への変換をしているということですよね。 であれば、strtol を使えばlongのオーバーフローが あるかどうかは検出できると思いますが? Manpage of STRTOL http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strtol.3.html アンダーフローもオーバーフローも起きなかった場合、strtol() 関数は変換された値を返す。オーバーフローした場合には LONG_MAX が返り、アンダーフローした場合には LONG_MIN が返る。オーバーフロー、アンダーフローのいずれの場合にも大域変数 errno には ERANGE が設定される。 strtoll() も同様であるが、LONG_MIN と LONG_MAX の代わりに LLONG_MIN と LLONG_MAX が返される。

DT50
質問者

お礼

ご回答ありがとうございます。 >オーバーフローした場合には LONG_MAX が返り、アンダーフローした場合には LONG_MIN が返る。 LONG_XXXが返ってくるだけで計算は続行されてしまいたが、errnoが検出されたかどうかをif文で使ったら、うまく処理を分岐させることができました。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.1

★最初に long 型でのチェックは出来ません。 ・同じ long 型では範囲を超えるためにチェックできません。  そこで『labs』というlong 型の絶対値を返す関数を利用します。  この関数で絶対値が返されたらば、一度『unsigned long』型の変数に代入します。 ・そして、その『unsigned long』型の変数で『LONG_MAX』よりも大きければエラーとします。  なお、『正数』の場合は『LONG_MAX - 1』を超えたらばエラーとします。負数の場合は  『LONG_MAX』以上ならエラーとしますが…。 ・これは long 型の範囲が『-2147483648』~『+2147483647』だからです。分かりますか? サンプル: unsigned long check; long value; ←これがチェックする long 型 check = (unsigned long)labs( value ); if ( value < 0 ){  if ( check > LONG_MAX ){   return( ERR );  } } else{  if ( check >= LONG_MAX ){   return( ERR );  } } 最後に: ・チェックする値の符号により次のようになります。  正数⇒最大『2147483647』まで正常値、『2147483648』以上はエラーです。  負数⇒最大『2147483648』まで正常値、『2147483649』以上はエラーです。 ・注意点としては、long 型よりも大きい数値(桁数で9桁以上など)は当然チェックできません。  この場合は、double 型に代入してチェックしますが、double 型よりも大きい数値を渡すと  またまたチェックできなくなります。どこまでチェックしますか? ・以上。おわり。→チェック範囲が『unsigned long』型に収まるならば上記のサンプルで可能。

DT50
質問者

お礼

Oh-Orange様 ご回答頂きありがとうございます。私はOh-Orange様にはたびたびお世話になっており、大変ありがたく思っています。 今後も宜しくお願い致します。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • Excel2007 条件付き書式 MIN及びMAXがうまくいかない

    Excel2007です。 条件付き書式で行方向にMAX(最大値)及びMIN(最小値)を塗りつぶしのため、画像で B2:G8を選択 セルの値が 次の値に等しい =MIN(B2:H2) 塗りつぶし赤 セルの値が 次の値に等しい =MAX(B2:H2) 塗りつぶし青 をせっていしたところ 画像のように複数のセルが塗りつぶされてしまいました。 書式設定方法に誤りがありますか? ある場合 条件付き書式の設定をどのようにすれば、最小値、最大値のみ書式を設定できますか。 お教え下さい。よろしくお願いします。

  • 最大値MAXを、最小値MINと(ABS?)で作りたい。

    最大値MAXを、最小値MINと(ABS?)で式を作りたい。 下記のデータのときに、 L123>0のとき  MAX(L123:L147)  最大値は1.181787 L123<0のとき  MIN((L123:L147)) 最小値は-2.725490です。 そこで、質問です。 下記のようにMINとABSを使い擬似最大値の式を作りました。 =MIN(ABS(L123:L147)) 擬似最大値は0.029886の結果を出したいのです。 しかし、「=MIN(ABS(L123:L147))」では「0.368062 」となります。 これはABS(L123)の値です。 上記「MINとABSの擬似最大値は0.029886」 となる式を教えてください。 (L123からL147のデータは下記のとおりです。 上記「MINとABSの擬似最大値は0.029886」 となる式を教えてください。) -0.368062 ,0.207454 ,0.085564 ,0.432480 ,1.099316 ,0.971129 ,1.181787,0.815206 ,1.118215 ,0.494807 ,0.602503 ,0.550321 ,0.029886 ,0.081306 ,-0.792841 ,-0.606078 ,-0.194655 ,-0.164800 ,-0.673720 ,-1.137632 ,-0.852141 ,-0.951941 ,-2.333839 ,-2.469809 ,-2.725490

  • MAX,MIN関数で空白の値を返したいのですが?

    MAX,MIN関数で空白の値を返したいのですが、中々上手く行きません。 何方か、ご教授頂けないでしょうか、宜しくお願い致します。 ※本題 MAX,MIN関数などの場合、真の0値が返されるので0が表示されると思います。 A1:AV10が未入力の場合:=MAX(A1:AV10) =0 又、AVERAGE関数の場合は、対象となるセルが未入力の場合(#DIV/0!)エラー表示されるので、下記載の様に空白の値を返す事が出来ます。 「=IF(ISERROR(AVERAGE(AN3:AV3))=TRUE,"",AVERAGE(AN3:AV3))」 そこで質問なのですが! MAX,MIN関数で値が入力されて無いとエラーを返す方法は有りますか? AVERAGEと同様に空白の値を返したいと思ってます。 ただ、差分で0が返ってくる場合が有り、オプションでゼロ値の非表示等は使えません。

  • ExcelのMINとMAXを下から(上から)2つ出したい。

    エクセルの集計表にて、 右端に合計と平均を出していて そこに最大値と最小値を付け足したいのですが とりあえず、 =MAX(A1:K1)や=MIN(A1:K1)で最大&最小を出す事は出来たのですが、 2番目に大きい数値、2番目に小さい数値を出すにはどうすれば 良いのでしょうか? 教えて下さい。宜しくお願い致します。

  • MAXデータから0を除いたMINデータを引きたい

    早速ですが、エクセルでセルに A1 2 A2 4 A3 0 A4 1 A5 3 がある場合、最大値は=MAX(A1:A5)で、0を除く最小値は=MIN(IF(A1:A5=0,"",A1:A5)で求められますがA6セルにMAX値から0を除くMIN値を表示させたく考えています。 計算式を=MAX(A1:A5)-MIN(A1:A5)だと0が含まれ、=MAX(A1:A5)-MIN(IF(A1:A5=0,"",A1:A5)だと、エラー(#VALUE!)となります。 どう設定すればよいか、ご知見ある方、ご教授よろしくお願いします。

  • 条件付書式設定がうまくできません

    EXCEL2000を使用しています。 ある範囲の最大値と最小値の色を変えたくて、 範囲指定をしてから 書式→条件付書式で 「セルの値が」「次の値に等しい」 「="max($E$3:$E$9)"」 と入力しました。 でも色は変わりません。 試しに最後の条件の欄に、「10」など具体的な数字を入れると変わります。 どなたか教えてください!

  • エクセルで最小値から0を除く方法

    早速ですが、エクセル入力したデータから最大値と最小値を求めようとしています。 最大値は=MAX(A1:A100)で求められるのですが、最小値には0が入っていると=MIN(A1*A100)では0となってしまいます。 0以外で最小値を求めたいのですが、どのように設定すればよいでしょうか? どなたかご教授いただけると助かります。

  • javaプログラムについて

    コマンドライン引数から複数の値を受け取り、それらの最大と最小を表示する、というプログラムなのですが。 class Maxmin{   public static void main (String[] args) {    int max=Integer.MIN_VALUE;    int min=Integer.MAX_VALUE;    for (int i=0; i<args.length; i++){     int num= Integer.parseInt(args[i]);     if(num>max)     max=num;     if(num<min)     min=num;    }    System.out.println("最大値は" + max + "です。");    System.out.println("最小値は" + min + "です。");  } } このプログラムでも問題なく表示されるのですが、MIN_VALUEとMAX_VALUEを使用せずに表示する事、と指摘を受けました。自分の中でぱっと思いついたのがこれだったのですが、他にはどのような方法があるのでしょうか?

    • ベストアンサー
    • Java
  • MIN関数が入力されているセルの行数に基づいてMIN関数の範囲を変える方法

    A列のA1がタイトル行で、その下に数字でデータが入力されています。 このとき、例えばB3にはA2からA3までの最小値、B4にはA2からA4までの最小値、・・・、B100にはA2からA100までの最小値、というように入力したいのです。 MIN関数とROW関数を組み合わせればよいと思うのですが、うまくいきません。 B列にはどのような式を入力すればよいでしょうか。

  • Excelのグラフでmin,maxの値指定したい。

    折れ線グラフを作る時、デフォルトでやるとグラフが偏ってしまって、変化が見えない。目盛りの範囲はどうして自動的に決めているんでしょうか。y座標のmin,maxの値を指定してグラフを作りたい。