-3

正如我所读到的,在有符号算术中存在许多未定义行为的情况。因此,我更喜欢使用无符号算术来计算结果(甚至是有符号的),这是在没有未定义情况的情况下指定的。

但是,当使用无符号算术获得结果时,最后一步,即转换为有符号值仍有待完成。

这是我编写的代码,我的问题是代码是否按照规则工作,即它是否安全,不依赖于一些未定义/未指定的行为?

/*
    function to safely convert given unsigned value
    to signed result having the required sign
        sign == 1 means the result shall be negative,
        sign == 0 means the result shall be nonnegative
    returns 1 on success, 0 on failure
*/
int safe_convert(unsigned value, int sign, int *result) {
    if (sign) {
        if (value > -(unsigned)INT_MIN) return 0; // value too big
        if (!value) return 0; // cannot convert zero to negative int
        *result = INT_MIN + (int)((-(unsigned)INT_MIN) - value);
    } else {
        if (value > (unsigned)INT_MAX) return 0; //value too big
        *result = (int)value;
    }
    return 1;
}

最终,有没有一种更简单的方法,不依赖于未定义/未指定的行为并做同样的事情?

4

4 回答 4

2

最终,有没有一种更简单的方法,不依赖于未定义的行为并做同样的事情?

short x = (short) value;

int y = (int) value;

但请确定您要转换的整数类型。value可能超出使用的有符号类型的范围。

于 2013-09-05T20:25:19.273 回答
1

从无符号到有符号的转换不是未定义的,而是实现定义的。来自 C++ 标准,第 4.7 章积分转换,第 3 段:

如果目标类型是有符号的,则如果它可以在目标类型(和位域宽度)中表示,则该值不变;否则,该值是实现定义的

因此,以下是定义的实现,并且在许多平台上正是您所期望的(环绕):

unsigned u = -1;
int i = (int)u;
于 2013-09-05T20:30:45.253 回答
1

唯一可能有问题的值是INT_MIN. 因此我会做类似的事情

int safe_convert(unsigned value, int sign, int *result) {
    if (sign) {
        if (value > -(unsigned)INT_MIN) return 0;           // value too big
        if (-(unsigned)INT_MIN > (unsigned)INT_MAX          // compile constant
             &&
             value == -(unsigned)INT_MIN)                   // special case       
           *result = INT_MIN;
        else *result = -(int)value;
    } else {
        if (value > (unsigned)INT_MAX) return 0; //value too big
        *result = (int)value;
    }
    return 1;
}

我不认为要求负零的情况证明错误返回是合理的。

于 2013-09-05T21:48:56.760 回答
1

sign为假(一个正数)的条件已经准备好处理好,当sign为真(一个负数)是棘手的。所以而不是:

if (value > -(unsigned)INT_MIN) return 0; // value too big
*result = INT_MIN + (int)((-(unsigned)INT_MIN) - value);

建议

// 1st half is for 2's compliment machines
// 2nd half is for symmetric ints like 1's compliment and signed ints
// Optimization will simplify the real code to 1 compare
if ((((INT_MIN + 1) == -INT_MAX) && (value > ((unsigned)INT_MAX + 1u))) ||
    (( INT_MIN      == -INT_MAX) && (value >  (unsigned)INT_MAX      ))) return 0;
int i = (int) value;
*result = -i;

测试INT_MIN == -INT_MAX可用于有条件地允许有符号零。

于 2013-09-05T22:02:30.780 回答