您的位置:首页 > 编程语言 > C语言/C++

C++移位与类型提升

2014-10-16 21:47 141 查看
一. C++中的移位运算

C++提供了>>和<<操作符,这是算术位移

先来复习一下算术位移和逻辑位移的区别

1.右移:

算术右移关心符号位,所以1000 0001右移变成1100 0000

逻辑右移不关心符号位,所以1000 0001右移变成0100 0000

2.左移

都不关心符号位,所以1000 0001左移都变成0000 0010

二. int(-1) >> 1

因为是算术右移,所以关心符号位,所以右移1位当然还是负数

首先数字在计算机里是用补码来保存的,所以-1的补码应该是1111 1111 1111 1111,然后往右移动一位,因为是算术右移,所以还是1111 1111 1111 1111,因此还是-1

三. char类型

char类型一般是有符号的,所以会有unsigned char的类型,但是一般不会用,不过在某些特定情况下,可以当成byte来用,因为C++本身是没有byte这种类型的,不过用char类型存储东西的时候不要想当然char是无符号的,否则移位的时候会出一些问题,不过char默认情况下也不一定是有符号的,这要看编译器的情况

测试1:

char x = -1;
unsigned char y = -1;
printf_s("%08x %08x\n",x>>1,y>>1); //ffffffff 0000007f

x表示打印无符号整数的16进制编码

测试2:

char x = 0x80;
unsigned char y = 0x80;
printf_s("%d %d\n",x,y); //-128 128


可见,结果差距还是挺大的,所以使用的时候要注意

四. 类型提升



对于上面的结果,我们或许会有点疑问,比如测试1,貌似x>>1的位数从1byte变成4byte了,而且,测试2貌似也有点问题,为什么打印结果会不一样呢

其实,测试的x和y在移位的时候都经历了类型提升,比如测试1,我们再测试一下:

类型提升测试:

char x = -1;
unsigned char y = -1;
printf_s("%d %d\n",sizeof(x),sizeof(y)); //1 1
printf_s("%d %d",sizeof(x>>1),sizeof(y>>1)); //4 4


发现移位后返回的竟然是一个int类型也就是4bytes的数据(其实不移位也是4bytes的数据)

printf_s("%d\n",sizeof(1111111111111111111)); //8
printf_s("%d\n",sizeof(1)); //4


我们再看下之前测试1的结果,发现类型提升后前面补的位不一样,对于有符号类型,如果是负数,前面全部补的是1,否则补0,而对于无符号类型,前面全部补的全是0

这样就能理解测试1的情况了,一开始x和y的二进制编码都是1111 1111,然后右移1位,由于要先进行类型提升,所以x变成1111 1111 1111 1111 1111 1111 1111 1111,而y变成0000 0000 0000 0000 0000 0000 1111 1111,由于是算术右移,所以关心符号位,而第一位x是1,所以是负数,右移不变,所以是ffffffff,而第一位y是0,所以是正数,右移1位变成0000
0000 0000 0000 0000 0000 0111 1111,因此是0000007f

其实上面的说法并不是很准确,printf("%x",a)或者printf("%u",b)打印的都是无符号的整数,而且是以32位为准,所以,不管什么东西,在printf打印的时候都会进行类型提升,而且就如之前所说,负数类型提升前面全部补1(只是猜测)

看一个例子:

char x = -1;
unsigned char y = -1;
printf_s("%x %x\n",x,y); //ffffffff ff
这里看到,就是没有强制打印8个16进制字符,但是x还是ffffffff共8位,所以打印的时候也进行了一次类型提升,但由于会忽视掉0,所以y只打印了ff两个字符

因此就能理解测试二的情况,为什么x是正数而y是负数,因为就算没有移位,在打印之前他们也进行了类型提升

再看一个例子:

char x = -1;
unsigned char y = -1;
printf_s("%x %x\n",x,y); //ffffffff ff
printf_s("%u %u\n",x,y); //4294967295 255
printf_s("%d %d\n",x,y); //-1 255
printf_s("%lld %lld\n",x,y);//1099511627775 0
u表示把数字当成无符号整数来打印

其中4294967295 = 2的32次方-1,109951162775 = 2的40次方-1

前三个都能理解,但第四个的打印结果的确让人很诧异

为什么第二个会是0呢?

如果这样理解,可能会好一些,print函数把x,y提升到32位,不过lld是打印64位有符号整数,这时候就开始借位,本来打印x,y,现在把y和x连接成一个64位整数再打印(也就是0000 00ff ffffffff,这里x和y顺序反转可能是是小端存储的原因吧)

int x = 0x12345678;
int y = 0x87654321;
int a = 0x00000001;
int b = 0x10000000;
printf_s("%llx %llx %llx %llx",x,y,a,b);//8765432112345678 1000000000000001 0 cccccccc7efde000
前面两个结果和估计的一样,后面的两个结果由于超出了范围所以打印出了奇怪的东西


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 类型提升 移位 char