当 size_t 溢出时,“<”和“>”运算符是否正常工作?
Do the "<" and ">" operators work correctly when size_t overflow?
我正在做一个更新 20 年前代码的项目,其中很多问题都与整数溢出有关。我想确保我正确地测试了溢出,所以我写了一个测试程序。它的输出让我吃惊。这是:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main (void) {
size_t largerNum,Num;
largerNum = 12;
Num = UINT_MAX;
printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum , Num, Num + 1);
largerNum = Num + 1;
printf("largerNum now = %u\n", largerNum);
if(largerNum < Num ){
printf("largerNum overflowed to %u\n", largerNum);
}
else {
printf("largerNum did not overflow: %u\n", largerNum);
}
printf("Is (0 < UINT_MAX)?\n");
(0 < UINT_MAX)?printf("YES\n"):printf("NO\n");
printf("Is (largerNum < Num)?\n");
(largerNum < Num)?printf("YES\n"):printf("NO\n");
return 0;
}
及其输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 0
largerNum did not overflow: 0
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
NO
我查看了其他一些帖子 here and here and read this paper,但它并没有使输出更清晰。有人以前看过这个吗?
编辑:我在从 size_t
更改为 unsigned long
时开始工作,这不应该做任何事情。
6 int main (void) {
7
8 unsigned long largerNum,Num;
9
10 largerNum = 12;
11 Num = UINT_MAX;
12
13 printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum , Num, Num + 1);
14
15 largerNum = Num + 2;
16
17 printf("largerNum now = %u\n", largerNum);
18
19 if(largerNum < Num ){
20 printf("largerNum overflowed to %u\n", largerNum);
21 }
22 else {
23 printf("largerNum did not overflow: %u\n", largerNum);
24 }
25
26 printf("Is (0 < UINT_MAX)?\n");
27
28 (0 < UINT_MAX)?printf("YES\n"):printf("NO\n");
29
30 printf("Is (largerNum < Num)?\n");
31
32 (largerNum < Num)?printf("YES\n"):printf("NO\n");
33
34
35 printf("largerNum = %u\n", largerNum);
36 printf("Num = %u\n", Num);
37
38 return 0;
39 }
输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 4294967295
编辑2:
阅读一些评论后,我将 'UINT_MAX' 替换为 'ULONG_MAX',三元运算符运行正常。然后我将 'size_t' 更改为 'unsigned long'。它仍然可以正常工作。令我感到奇怪的是,在我的机器上,'size_t'、'unsigned int' 和 'unsigned long' 都是相同的字节数,而 'UINT_MAX' 和 'ULONG_MAX' 是相同的值,但尽管一切都相同,但该三元运算符仍然会失败。也许不一样?这打乱了我对 C 的理解。
感兴趣的朋友,工作代码:
6 int main (void) {
7 /* Can be size_t or unsigned long */
8 size_t largerNum,Num;
9
10 largerNum = 12;
11 Num = ULONG_MAX;
12
13 printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum , Num, Num + 1);
14
15 largerNum = Num + 2;
16
17 printf("largerNum now = %u\n", largerNum);
18
19 if(largerNum < Num ){
20 printf("largerNum overflowed to %u\n", largerNum);
21 }
22 else {
23 printf("largerNum did not overflow: %u\n", largerNum);
24 }
25
26 printf("Is (0 < ULONG_MAX)?\n");
27
28 (0 < ULONG_MAX)?printf("YES\n"):printf("NO\n");
29
30 printf("Is (largerNum < Num)?\n");
31
32 (largerNum < Num)?printf("YES\n"):printf("NO\n");
33
34
35 printf("largerNum = %u\n", largerNum);
36 printf("Num = %u\n", Num);
37
38 return 0;
39 }
输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < ULONG_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 4294967295
最终编辑:
阅读更多评论后,我发现我的 printf()
陈述是错误的。谢谢大家的帮助,现在一切都变得更有意义了。 =D
最终代码:
6 int main (void) {
7
8 unsigned long largerNum,Num;
9
10 largerNum = 12;
11 Num = ULONG_MAX;
12
13 printf("largerNum = %zu\nNum = %zu\nNum + 1 = %zu\n", larger Num, Num, Num + 1);
14
15 largerNum = Num + 2;
16
17 printf("largerNum now = %zu\n", largerNum);
18
19 if(largerNum < Num ){
20 printf("largerNum overflowed to %zu\n", largerNum);
21 }
22 else {
23 printf("largerNum did not overflow: %zu\n", largerNum);
24 }
25
26 printf("Is (0 < ULONG_MAX)?\n");
27
28 (0 < ULONG_MAX)?printf("YES\n"):printf("NO\n");
29
30 printf("Is (largerNum < Num)?\n");
31
32 (largerNum < Num)?printf("YES\n"):printf("NO\n");
33
34
35 printf("largerNum = %zu\n", largerNum);
36 printf("Num = %zu\n", Num);
37
38 return 0;
39 }
最终输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 18446744073709551615
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < ULONG_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 18446744073709551615
我猜你的平台有 64 位 size_t
,你使用错误的格式说明符来打印 size_t
,这是 undefined behavior 并导致误导性的输出。
至 print size_t
s,在 gcc 和 clang 上使用 %zu
,在 MSVC 上使用 %Iu
。或者忘记所有这些并使用 std::cout
打印结果。
在 VS2015 上使用 %Iu
,我在 64 位编译器上得到的输出是
largerNum = 12
Num = 4294967295
Num + 1 = 4294967296
largerNum now = 4294967296
largerNum did not overflow: 4294967296
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
NO
只需添加到@Praetorian 的答案并显示类型安全的实现:
#include <iostream>
#include <limits>
int main (void) {
using std::size_t;
using std::cout;
size_t largerNum = 12;
size_t Num = std::numeric_limits<size_t>::max();
cout << "largerNum = " << largerNum << "\nNum = " << Num << "\nNum + 1 = " << Num + 1 << "\n";
largerNum = Num + 1;
cout << "largerNum now = " << largerNum << "\n";
if(largerNum < Num ){
cout << "largerNum overflowed to " << largerNum << "\n";
}
else {
cout << "largerNum did not overflow: " << largerNum << "\n";
}
cout << "Is (0 < Unsigned Maximum)?\n";
(0 < std::numeric_limits<size_t>::max())?cout << "YES\n":cout << "NO\n";
cout << "Is (largerNum < Num)?\n";
(largerNum < Num)?cout << "YES\n":cout << "NO\n";
return 0;
}
因此:'printf' 在 C++ 中不是一个好的选择,它不是类型安全的(尽管好的编译器可以识别无效的格式说明符)。另一方面,iostream 运算符很麻烦(对许多人来说),如果必须将输出翻译成不同的语言(例如:gnu getline),则效果不佳。您可以在网上浏览类型安全的格式字符串(例如:boost::format)
我正在做一个更新 20 年前代码的项目,其中很多问题都与整数溢出有关。我想确保我正确地测试了溢出,所以我写了一个测试程序。它的输出让我吃惊。这是:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main (void) {
size_t largerNum,Num;
largerNum = 12;
Num = UINT_MAX;
printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum , Num, Num + 1);
largerNum = Num + 1;
printf("largerNum now = %u\n", largerNum);
if(largerNum < Num ){
printf("largerNum overflowed to %u\n", largerNum);
}
else {
printf("largerNum did not overflow: %u\n", largerNum);
}
printf("Is (0 < UINT_MAX)?\n");
(0 < UINT_MAX)?printf("YES\n"):printf("NO\n");
printf("Is (largerNum < Num)?\n");
(largerNum < Num)?printf("YES\n"):printf("NO\n");
return 0;
}
及其输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 0
largerNum did not overflow: 0
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
NO
我查看了其他一些帖子 here and here and read this paper,但它并没有使输出更清晰。有人以前看过这个吗?
编辑:我在从 size_t
更改为 unsigned long
时开始工作,这不应该做任何事情。
6 int main (void) {
7
8 unsigned long largerNum,Num;
9
10 largerNum = 12;
11 Num = UINT_MAX;
12
13 printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum , Num, Num + 1);
14
15 largerNum = Num + 2;
16
17 printf("largerNum now = %u\n", largerNum);
18
19 if(largerNum < Num ){
20 printf("largerNum overflowed to %u\n", largerNum);
21 }
22 else {
23 printf("largerNum did not overflow: %u\n", largerNum);
24 }
25
26 printf("Is (0 < UINT_MAX)?\n");
27
28 (0 < UINT_MAX)?printf("YES\n"):printf("NO\n");
29
30 printf("Is (largerNum < Num)?\n");
31
32 (largerNum < Num)?printf("YES\n"):printf("NO\n");
33
34
35 printf("largerNum = %u\n", largerNum);
36 printf("Num = %u\n", Num);
37
38 return 0;
39 }
输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 4294967295
编辑2:
阅读一些评论后,我将 'UINT_MAX' 替换为 'ULONG_MAX',三元运算符运行正常。然后我将 'size_t' 更改为 'unsigned long'。它仍然可以正常工作。令我感到奇怪的是,在我的机器上,'size_t'、'unsigned int' 和 'unsigned long' 都是相同的字节数,而 'UINT_MAX' 和 'ULONG_MAX' 是相同的值,但尽管一切都相同,但该三元运算符仍然会失败。也许不一样?这打乱了我对 C 的理解。
感兴趣的朋友,工作代码:
6 int main (void) {
7 /* Can be size_t or unsigned long */
8 size_t largerNum,Num;
9
10 largerNum = 12;
11 Num = ULONG_MAX;
12
13 printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum , Num, Num + 1);
14
15 largerNum = Num + 2;
16
17 printf("largerNum now = %u\n", largerNum);
18
19 if(largerNum < Num ){
20 printf("largerNum overflowed to %u\n", largerNum);
21 }
22 else {
23 printf("largerNum did not overflow: %u\n", largerNum);
24 }
25
26 printf("Is (0 < ULONG_MAX)?\n");
27
28 (0 < ULONG_MAX)?printf("YES\n"):printf("NO\n");
29
30 printf("Is (largerNum < Num)?\n");
31
32 (largerNum < Num)?printf("YES\n"):printf("NO\n");
33
34
35 printf("largerNum = %u\n", largerNum);
36 printf("Num = %u\n", Num);
37
38 return 0;
39 }
输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < ULONG_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 4294967295
最终编辑:
阅读更多评论后,我发现我的 printf()
陈述是错误的。谢谢大家的帮助,现在一切都变得更有意义了。 =D
最终代码:
6 int main (void) {
7
8 unsigned long largerNum,Num;
9
10 largerNum = 12;
11 Num = ULONG_MAX;
12
13 printf("largerNum = %zu\nNum = %zu\nNum + 1 = %zu\n", larger Num, Num, Num + 1);
14
15 largerNum = Num + 2;
16
17 printf("largerNum now = %zu\n", largerNum);
18
19 if(largerNum < Num ){
20 printf("largerNum overflowed to %zu\n", largerNum);
21 }
22 else {
23 printf("largerNum did not overflow: %zu\n", largerNum);
24 }
25
26 printf("Is (0 < ULONG_MAX)?\n");
27
28 (0 < ULONG_MAX)?printf("YES\n"):printf("NO\n");
29
30 printf("Is (largerNum < Num)?\n");
31
32 (largerNum < Num)?printf("YES\n"):printf("NO\n");
33
34
35 printf("largerNum = %zu\n", largerNum);
36 printf("Num = %zu\n", Num);
37
38 return 0;
39 }
最终输出:
[afischer@susm603 /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 18446744073709551615
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < ULONG_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 18446744073709551615
我猜你的平台有 64 位 size_t
,你使用错误的格式说明符来打印 size_t
,这是 undefined behavior 并导致误导性的输出。
至 print size_t
s,在 gcc 和 clang 上使用 %zu
,在 MSVC 上使用 %Iu
。或者忘记所有这些并使用 std::cout
打印结果。
在 VS2015 上使用 %Iu
,我在 64 位编译器上得到的输出是
largerNum = 12
Num = 4294967295
Num + 1 = 4294967296
largerNum now = 4294967296
largerNum did not overflow: 4294967296
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
NO
只需添加到@Praetorian 的答案并显示类型安全的实现:
#include <iostream>
#include <limits>
int main (void) {
using std::size_t;
using std::cout;
size_t largerNum = 12;
size_t Num = std::numeric_limits<size_t>::max();
cout << "largerNum = " << largerNum << "\nNum = " << Num << "\nNum + 1 = " << Num + 1 << "\n";
largerNum = Num + 1;
cout << "largerNum now = " << largerNum << "\n";
if(largerNum < Num ){
cout << "largerNum overflowed to " << largerNum << "\n";
}
else {
cout << "largerNum did not overflow: " << largerNum << "\n";
}
cout << "Is (0 < Unsigned Maximum)?\n";
(0 < std::numeric_limits<size_t>::max())?cout << "YES\n":cout << "NO\n";
cout << "Is (largerNum < Num)?\n";
(largerNum < Num)?cout << "YES\n":cout << "NO\n";
return 0;
}
因此:'printf' 在 C++ 中不是一个好的选择,它不是类型安全的(尽管好的编译器可以识别无效的格式说明符)。另一方面,iostream 运算符很麻烦(对许多人来说),如果必须将输出翻译成不同的语言(例如:gnu getline),则效果不佳。您可以在网上浏览类型安全的格式字符串(例如:boost::format)