-1L和0U比较大小,32为系统和64位系统有何不同?

24 篇文章 0 订阅

下文所有说法仅针对linux等long类型在32位和64位程序中,长度不一样的系统成立,因为WIndows系统long不论是32位还是64位,都是4字节。

下面的程序在32位和64位下,会输出什么结果?

  1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5     long la = -1l;
  6     unsigned int uib = 0u;
  7 
  8     if(la<uib)
  9     {
 10         printf("-1l<0u\n");
 11     }
 12     else
 13     {
 14         printf("-1l>0u\n");
 15     }
 16     return 0;
 17 }

在Linux系统使用GCC编译,运行,结果如下:

$ gcc cmp.c -m32 -g -o cmp32
[nereus@nereusp cpp]$ ./cmp32
-1l>0u
$ gcc cmp.c -g -o cmp64
$ ./cmp64
-1l<0u

可以发现在32位程序中,出现了-1L>0U的情况,为什么呢?

还是先来看看汇编吧,为了让汇编尽可能的简单,我把代码中的stdio部分去除了,修改后的代码如下:

 1 int main()
  2 {
  3     long la = -1l;
  4     unsigned int uib = 0u;
  5 
  6     int c = la<uib;
  7     return 0;
  8 }

32位程序反汇编:

080483db <main>:
int main()
{
 80483db:	55                   	push   %ebp
 80483dc:	89 e5                	mov    %esp,%ebp
 80483de:	83 ec 10             	sub    $0x10,%esp
	long la = -1l;
 80483e1:	c7 45 fc ff ff ff ff 	movl   $0xffffffff,-0x4(%ebp)
	unsigned int uib = 0u;
 80483e8:	c7 45 f8 00 00 00 00 	movl   $0x0,-0x8(%ebp)

	int c = la<uib;
 80483ef:	8b 45 fc             	mov    -0x4(%ebp),%eax
 80483f2:	3b 45 f8             	cmp    -0x8(%ebp),%eax
 80483f5:	0f 92 c0             	setb   %al
 80483f8:	0f b6 c0             	movzbl %al,%eax
 80483fb:	89 45 f4             	mov    %eax,-0xc(%ebp)
	return 0;
 80483fe:	b8 00 00 00 00       	mov    $0x0,%eax
}

64位程序反汇编:

00000000004004d6 <main>:
int main()
{
  4004d6:	55                   	push   %rbp
  4004d7:	48 89 e5             	mov    %rsp,%rbp
	long la = -1l;
  4004da:	48 c7 45 f8 ff ff ff 	movq   $0xffffffffffffffff,-0x8(%rbp)
  4004e1:	ff 
	unsigned int uib = 0u;
  4004e2:	c7 45 f4 00 00 00 00 	movl   $0x0,-0xc(%rbp)

	int c = la<uib;
  4004e9:	8b 45 f4             	mov    -0xc(%rbp),%eax
  4004ec:	48 3b 45 f8          	cmp    -0x8(%rbp),%rax
  4004f0:	0f 9f c0             	setg   %al
  4004f3:	0f b6 c0             	movzbl %al,%eax
  4004f6:	89 45 f0             	mov    %eax,-0x10(%rbp)
	return 0;
  4004f9:	b8 00 00 00 00       	mov    $0x0,%eax
}

从上面的汇编可以发现,

在32位程序中,-1L和0U比较的时候,是先把long转换成unsigned int再进行比较的,所以是对无符号的0xFFFFFFFF和0x00000000进行比较。

在64位程序中,-1L和0U比较的时候,是先把unsigned int转换成long再进行比较的,所以是对无符号的0xFFFFFFFF和0x00000000进行比较。

比较规则如下:

if(两者长度不一致)
{
	/* 将长度小者转换成长度大者的数据类型 */
}
if(有符号和无符号数比较)
{
	/* 将有符号数转换成无符号数 */
}

/ * 进行比较 */

在32位系统下,比较过程如下:

(1)先判断-1L和0U的长度,都是4字节,不转换;

(2)判断符号类型,-1L是有符号,0u是无符号,将-1L转换成无符号数,0xFFFFFFFF;

(3)进行比较,无符号数0xFFFFFFFF和0x00000000比较,前者大。

在64位系统下,比较过程如下:

(1)先判断-1L和0U的长度,0U是4字节,-1L是8字节,不一致,将0U转换为长度更大者long类型;

(2)判断符号类型,此时两者都是long类型,都是有符号数,不转换;

(3)进行比较,有符号数0xFFFFFFFF FFFFFFFF和0x00000000 00000000比较,后者是正数,后者大。

Q:怎样避免这种情况?

答:比较大小之前,一定要将两被比较数类型转换成同一类型!

对于上面的代码,只要进行如下修改,就能避免这种情况:

把uib转换成long再比较

  1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5     long la = -1l;
  6     unsigned int uib = 0u;
  7 
  8     if(la<((long)uib))  //把uib转换成long再比较
  9     {
 10         printf("-1l<0u\n");
 11     }
 12     else
 13     {
 14         printf("-1l>0u\n");
 15     }
 16     return 0;
 17 }

修改之后,不论32为还是64位,输出都是

$ gcc cmp.c -o cmp32 -g -m32
$ ./cmp32
-1l<0u
$ gcc cmp.c -o cmp64 -g
$ ./cmp64
-1l<0u
$ 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值