做“<”和“>”当size_t溢出时,运算符是否正常工作?

时间:2015-05-20 16:09:15

标签: c printf overflow operator-keyword size-t

我正在开发一个更新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

我查看了其他一些帖子herehere并阅读了此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

EDIT2:

在阅读了一些评论后,我将'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

2 个答案:

答案 0 :(得分:7)

我的猜测是您的平台有64位size_t,并且您使用了错误的格式说明符来打印size_t,这是undefined behavior并导致误导输出。

print size_ts,请在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

答案 1 :(得分:1)

只需添加@ 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)