【发布时间】:2018-08-22 17:29:13
【问题描述】:
考虑以下代码:
main()
{
int assigned = 4294967295; // Max unsigned integer value on 32-bits arch
char input[] = "4294967295";
int sscanned;
unsigned int result = sscanf(input, "%d", &sscanned);
printf ("scanned %u elements : %d\n
"Assigned j = %d\n",
result, sscanned, assigned);
return 0;
}
当为 32 位 arch 编译时(使用编译命令:gcc -Wall -Wextra -std=c11 -pedantic -m32 test_sscanf.c -o test_sscanf32),它会发出一个关于“从 'long long int' 转换为 'int' 的值从 '4294967295' 的转换中溢出的预期警告到'-1' [-Woverflow]”。
现在看到结果了:
> ./test_sscanf32
scanned 1 elements : 2147483647
Assigned j = -1
虽然assigned 值已通过二进制补码表示(-1 = -2^31 + 2^30 + ... + 2^ 0),另一方面,scanned 值显然已取消其 MSB,导致其缩小到值 2147483647 = 2^31 - 1。
所以我的问题是:在 n 位机器上 上处理 最大 n 位整数值 的这种差异有什么理由(知道在64 位拱门,发生相同的行为)?
在给定的架构上,程序员是否无权期望sscanf 会像赋值一样对待值?
【问题讨论】:
-
使用
%u读取无符号整数。 -
@wildplasser 我知道这一点。但这不是我的问题!我的问题与为什么
sscanf处理 有符号的最大整数值 是通过丢弃它的 MSB 来处理的,而赋值只是用二进制补码转换它? -
赋值由编译器完成;扫描由库例程完成。他们可能使用不同的算法从 ascii 字符中获取值。正如 wildplasser 所说,使用 %u 读取 unsigned;否则结果未定义。
-
...例如,编译器本身是 64 位并截断值,但运行时库例程是 32 位并溢出。
-
"...为什么 sscanf 通过丢弃它的 MSB 来处理有符号的最大整数值"。这不是发生的事情。试试
char input[] = "4294967290";(最后一位是 0 而不是 5)。我怀疑结果仍然是2147483647。查看strtol()以获得洞察力。
标签: c scanf integer-overflow twos-complement