5

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

4 に答える 4

2

Errnoはプロセッサが設定する変数ではありません。システム コールと一部の標準関数でエラーを報告するためにのみ使用されます。

c < c + 1ループの反復ごとに検証することを除いて、あなたが求めているものを検出するための手法はわかりません。

編集:いくつかの調査の後、ステータスレジスタに関するこのウィキペディアを見つけました。ステータスレジスタは、そのようなエラーを示すCPUフラグです。

于 2012-10-13T01:15:13.687 に答える
2

私が理解していることから、errno関数によって設定されます。独自の関数を作成しない限り、加算オーバーフロー エラーは検出されません。結果がオペランドの 1 つよりも小さいかどうかをテストできます。

#include <stdio.h>
#include <errno.h>

int main(int argc, char* argv[]) {
    unsigned char c = 0, result = 0;
    int i;

    for (i = 0; i< 300; i++) {
        result = c + 1;
        if (result < c) {// we have a range error
            printf("Overflow. c = %u\n", result);
        } else {
            c = result;
            printf("No error. c = %u\n", c);
        }
    }
    return 0;
}
于 2012-10-13T01:22:47.437 に答える
2

errno他社製という点に加えunsigned char、カウンターに使用しています。符号なしの型は、ラップアラウンドするように明示的に定義されています。言い換えると、 が8 ビットのc=255; c=c+1;場合を計算してもエラーにはなりません。結果は常にです。cunsigned char0

于 2012-10-13T07:17:53.470 に答える
1

整数オーバーフローは未定義の動作です。未定義の動作は検出可能な状態ではありません。エンドゲームです。未定義の動作を呼び出すと、プログラムの状態について結論を出すことはできません。

それ以外errnoは、算術式とは何の関係もありません。ライブラリ関数からのエラーを報告するために使用されます。

于 2012-10-13T01:59:26.593 に答える