发生溢出,但errno不是ERANGE。这是怎么发生的?

时间:2012-10-13 01:01:38

标签: c overflow errno

我正在尝试使用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;
}

我预计这会在我们添加1到255的位置发出溢出错误,但没有错误。这是(截断的)输出:

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

有人可以解释为什么它没有检测到错误,以及我如何更改错误或以其他方式创建一个可以检测我的值是否溢出的函数?注意:最终我希望使用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 个答案:

答案 0 :(得分:2)

Errno不是处理器设置变量,它仅由系统调用和一些标准函数用于支持错误。

我不知道任何检测你问的方法,在每次循环迭代时验证是否c < c + 1

编辑:经过一些研究,我找到了this维基百科有关状态寄存器的信息,它们是指示此类错误的CPU标志。

答案 1 :(得分:2)

根据我的理解,errno由函数设置。除非您创建自己的函数,否则它不会检测到添加溢出错误。您可以测试结果是否少于一个操作数。

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

答案 2 :(得分:2)

除了其他人提出的关于errno的观点之外,您还在使用unsigned char作为计数器。明确定义了无符号类型以进行环绕。换句话说,当c=255; c=c+1;为8位c时,计算unsigned char并非错误:结果始终为0

答案 3 :(得分:1)

整数溢出是未定义的行为。未定义的行为不是可检测的条件。这是最后的结局。一旦调用了未定义的行为,就无法得出有关程序状态的任何结论。

除此之外,errno与算术表达式无关。它用于报告库函数的错误。

相关问题