#include <stdio.h>
int reverse(int);
int reverse(int x) {
int negative = 0;
if (x < 0)
negative = x;
if (negative != 0) {
x = 0 - x;
}
int y = 0, temp;
while (x > 0) {
temp = x % 10;
x = x / 10;
y = (y * 10) + temp;
}
if (negative == 0) {
return y;
} else {
return 0 - y;
}
}
int main() {
int x, y;
printf("Enter your number: \n");
scanf("%d", &x);
y = reverse(x);
printf("The reversed number is: %d\n", y);
return 0;
}
此程序将反转带符号的整数。我无法检查受尊敬的整数y是否超出范围。我无法在溢出主题上弄清楚。如果我要求编译器使用scanf扫描整数并输入超出整数范围的整数,会发生什么?存储时值会改变吗?
答案 0 :(得分:1)
您似乎对溢出有两个不同的问题。
答案如下。
y <= INT_MAX / 10
,则可以确保y * 10
不会溢出。 ... + temp
也是如此。scanf
和朋友没有其他方法来保护您免受溢出的影响,除了限制字段宽度并因此限制输入范围(但是,如果您正在读取小数,则不能将范围完全限制为INT_MAX
)。如果扫描的值不适合目标类型,则行为未定义。安全转换确切范围的字符串的唯一方法是与strtol
和朋友。这些函数检测溢出并相应地设置errno
。答案 1 :(得分:0)
在标准C中,溢出是一个例外情况,然后按标准未定义行为。摘自n1570 for C11,6.5表达式§5:
如果在表达式的求值过程中发生异常情况(即 结果没有在数学上定义,或者不在其可表示的值范围内 类型),行为是不确定的。
这意味着您不能按照标准定义溢出方式。话虽这么说,大多数编译器只是保留结果的低阶位以适合类型表示,而忽略最高阶位。这就是MSVC,gcc和clang的作用。
从现在开始,我将假设您的系统使用int32_t
(分别为int16_t
或int64_t
)来签名int并忽略溢出。它不是每个标准都强制要求的,但足够通用,很可能是您的系统所要做的。
您的代码中可能有2个溢出。首先是scanf
函数:如@ n.m。所说,如果输入序列不适合该类型,则对于该函数系列的行为不作任何说明。我将假定提交的数字可以作为带符号的int接受(介于INT_MIN和INT_MAX之间)。无论如何,让用户检测到它是微不足道的:仅显示x
:如果它不是唯一键入的数字,则发生溢出。
第二个在这里:
y = (y * 10) + temp;
在这里,通过执行反向操作并控制一切都很好,很容易测试溢出:
int next = (y * 10) + temp;
if ((next < 0) || (y != (next - temp) / 10)) {
// an overflow occured...
...
从理论上讲,没有什么可以保证否定一个正整数是一个有效的负整数,但这对于intXX_t
类型是正确的,因此足以检测到reverse
函数中的溢出