errno
オーバーフローの原因となる操作を実行したかどうかを検出するために利用しようとしています。しかし、意図的にオーバーフローする関数を作成しましたが、それerrno == ERANGE
は誤りです。何が起きてる?
コードは次のとおりです。
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]) {
unsigned char c = 0;
int i;
for (i = 0; i< 300; i++) {
errno = 0;
c = c + 1;
if (errno == ERANGE) {// we have a range error
printf("Overflow. c = %u\n", c);
} else {
printf("No error. c = %u\n", c);
}
}
return 0;
}
これにより、255に1を追加した時点でオーバーフローエラーが発生すると予想しましたが、エラーはありません。(切り捨てられた)出力は次のとおりです。
No error. c = 245
No error. c = 246
No error. c = 247
No error. c = 248
No error. c = 249
No error. c = 250
No error. c = 251
No error. c = 252
No error. c = 253
No error. c = 254
No error. c = 255
No error. c = 0
No error. c = 1
No error. c = 2
No error. c = 3
No error. c = 4
No error. c = 5
No error. c = 6
No error. c = 7
No error. c = 8
No error. c = 9
誰かがエラーを検出しない理由と、エラーを変更したり、値がオーバーフローしたかどうかを検出できる関数を作成したりする方法を説明できますか?注:最終的にはsを使用してこれを実行したいlong int
ので、単純にそれをより大きなデータ型に変換することはできません。
編集:
それ以来、積分データ型の加算と乗算からそれぞれオーバーフローを検出するためのいくつかの単純な関数を見つけました。すべての状況を網羅しているわけではありませんが、多くの状況を網羅しています。
乗算:
int multOK(long x, long y)
/* Returns 1 if x and y can multiply without overflow, 0 otherwise */
{
long p = x*y;
return !x || p/x == y;
}
署名された追加:
int addOK(long x, long y)
/* Returns 1 if x and y can add without overflow, 0 otherwise */
{
long sum = x+y;
int neg_over = (x < 0) && (y < 0) && (sum >= 0);
int pos_over = (x >= 0) && (y >= 0) && (sum < 0);
return !neg_over && !pos_over;
}
符号なし加算:
int unsignedAddOK(unsigned long x, unsigned long y)
/* Returns 1 if x and y can add without overflow, 0 otherwise */
{
unsigned long sum = x+y;
return sum > x && sum > y;
}