负数居然比正数大?无符号整型与整形混用的后果

简介: 负数居然比正数大?无符号整型与整形混用的后果

在之前写一个代码的过程中,没有注意细节,对于一个文件的大小,就默认定义为unsigned int类型了,然后,每次遍历一段之后,就减去遍历的长度,这个unsigned int类型的值,在正常的测试下,并没有出现什么问题,但是到了真正的压力测试,大量的fuzzer来进行测试的时候,出现了一个看起来很奇怪的bug,正数居然比负数小?这是什么原因?我们看看下面的代码:

  int v1 = -1;
  unsigned int v2 = 5;
  if (v2 < v1)
  {
    printf("error\n");
  }
  else
  {
    printf("rigth\n");
  }

按照我们的思路,该代码输出的肯定是right,因为很明显5比-1要大。但是最终输出的结果是:

image.png

说明在比较的时候,确实-1大于了5?为什么会这样呢?接下来我们来看一段汇编:

  int v1 = -1;
00A5180E  mov         dword ptr [v1],0FFFFFFFFh  
  unsigned int v2 = 5;
00A51815  mov         dword ptr [v2],5  
  if (v2 < v1)
00A5181C  mov         eax,dword ptr [v2]  
00A5181F  cmp         eax,dword ptr [v1]  
00A51822  jae         main+43h (0A51833h)  
  {
    printf("error\n");
00A51824  push        offset string "error\n" (0A56B30h)  
00A51829  call        _printf (0A51320h)  
00A5182E  add         esp,4  
  }
  else
00A51831  jmp         main+50h (0A51840h)  
  {
    printf("rigth\n");
00A51833  push        offset string "rigth\n" (0A56B38h)  
00A51838  call        _printf (0A51320h)  
00A5183D  add         esp,4  
  }

这段汇编代码中我认为最重要的是:

image.png

大家注意看这条指令jae,这条汇编跳转指令比较的是两个无符号整数的值,如果我们的-1被当作一个无符号的数,那么它比5大,那也就不足为奇了。

接下来看看如果是用两个int型的变量,会有什么结果?

  int v4 = -1;
  int v3 = 5;
  if (v3 < v4)
  {
    printf("error\n");
  }
  else
  {
    printf("rigth\n");
  }

image.png

结果是rigth,也就是我们期盼的结果,那么我们再来看看汇编:

  int v4 = -1;
00DC180E  mov         dword ptr [v4],0FFFFFFFFh  
  int v3 = 5;
00DC1815  mov         dword ptr [v3],5  
  if (v3 < v4)
00DC181C  mov         eax,dword ptr [v3]  
00DC181F  cmp         eax,dword ptr [v4]  
00DC1822  jge         main+43h (0DC1833h)  
  {
    printf("error\n");
00DC1824  push        offset string "error\n" (0DC6B30h)  
00DC1829  call        _printf (0DC1320h)  
00DC182E  add         esp,4  
  }
  else
00DC1831  jmp         main+50h (0DC1840h)  
  {
    printf("rigth\n");
00DC1833  push        offset string "rigth\n" (0DC6B38h)  
00DC1838  call        _printf (0DC1320h)  
00DC183D  add         esp,4  
  }

这段汇编代码中使用的jpe汇编,是比较两个有符号整数的跳转指令:


image.png

所以我们就得到了想要的正确结果。


在写代码的过程中,要切记在表达式中混用带符号和不带符号数,因为当不带符号的数和一个带符号的负数比较时,负数会发生位拓展。


“怅寥廓,问苍茫大地,谁主沉浮?”

目录
相关文章
|
1月前
|
存储 C语言 C++
截断&&整型提升&&算数转换
截断&&整型提升&&算数转换
|
8月前
|
C语言
C语言之将十进制整数转换为任意进制整数
C语言之将十进制整数转换为任意进制整数
182 0
|
9月前
|
C语言
C语言:截断+整型提升+算数转换练习
截断+整型提升+算数转换练习
45 0
|
1月前
|
存储 C语言
C中负数的存储形式 | 位运算符
C中负数的存储形式 | 位运算符
16 0
|
1月前
|
C语言
【C语言】如何只打印小数的有效数字位数且不补0
【C语言】如何只打印小数的有效数字位数且不补0
25 0
【C语言】如何只打印小数的有效数字位数且不补0
|
1月前
|
C语言
C语言两个数相除怎么得到浮点数
有些时候,使用C语言的相除运算符计算两个变量相除运算结果,可是却无法保留小数,比如3/2,打印输出是1,而不是1.5之类有小数的值。这是为什么呢?可能有两种原因,如下
35 2
|
1月前
|
编译器 C语言 C++
整形提升和算数转换
整形提升和算数转换
24 0
|
8月前
|
存储 人工智能 编译器
C语言之(有关%d和%u的有关内容,输出方法)(有符号和无符号在内存中的存储情况)(整形无符号数和有符号数是如何进行计算的,整形无符号数和有符号数在循环中的应用举例)
C语言之(有关%d和%u的有关内容,输出方法)(有符号和无符号在内存中的存储情况)(整形无符号数和有符号数是如何进行计算的,整形无符号数和有符号数在循环中的应用举例)
298 0
|
C语言
已知一个整数,如何判断这个整数是无符号的?
已知一个整数,如何判断这个整数是无符号的?
71 0
|
C++
C++ 各种无符号整型能够在溢出之前计算出斐波那契数列的最大项数是几?答案是24、47、93
C++ 各种无符号整型能够在溢出之前计算出斐波那契数列的最大项数是几?答案是24、47、93
61 0