正如我所读到的,在有符号算术中,存在许多未定义行为的情况。因此,我更喜欢使用无符号算法计算结果(甚至是有符号算法),无符号算法是在没有未定义的情况下指定的。
但是,当使用无符号算术(最后一步)获得结果时,仍然需要转换为有符号值。
这是我编写的代码,我的问题是代码是否符合规则,即它是否安全,不依赖于某些未定义/未指定的行为?
/*
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;
}
最终,有没有一种方法更简单,不依赖于未定义/未指定的行为并做同样的事情?
答案 0 :(得分:2)
最终,有没有一种方法更简单,不依赖于未定义的行为并做同样的事情?
short x = (short) value;
int y = (int) value;
但请确保您投射的是什么积分类型。 value
可能超出所使用的签名类型范围。
答案 1 :(得分:1)
从未签名到签名的转换未定义,但实现已定义。从C ++标准,第4.7章完整转换,第3段:
如果目标类型已签名,则该值不会更改,如果它可以在目标类型中表示(和 位域宽度);否则,该值是实现定义的
因此,以下是实现定义,并且在许多平台上完全符合您的预期(环绕):
unsigned u = -1;
int i = (int)u;
答案 2 :(得分: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;
}
我不认为要求负零的情况证明错误返回是合理的。
答案 3 :(得分: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
测试可用于有条件地允许有符号的零。