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:
x表示打印无符号整数的16进制编码
测试2:
可见,结果差距还是挺大的,所以使用的时候要注意
四. 类型提升
对于上面的结果,我们或许会有点疑问,比如测试1,貌似x>>1的位数从1byte变成4byte了,而且,测试2貌似也有点问题,为什么打印结果会不一样呢
其实,测试的x和y在移位的时候都经历了类型提升,比如测试1,我们再测试一下:
类型提升测试:
发现移位后返回的竟然是一个int类型也就是4bytes的数据(其实不移位也是4bytes的数据)
我们再看下之前测试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(只是猜测)
看一个例子:
因此就能理解测试二的情况,为什么x是正数而y是负数,因为就算没有移位,在打印之前他们也进行了类型提升
再看一个例子:
其中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顺序反转可能是是小端存储的原因吧)
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 ffu表示把数字当成无符号整数来打印
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
其中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++混合运算的类型提升和溢出
- c++算术运算和位运算中类型转换和类型提升规则和方法
- c++算术运算和位运算中类型转换和类型提升规则和方法
- C++混合运算的类型提升和溢出
- c++高级---C语言中的类型提升——基础概念,但还有很多人搞不清
- c++中类型提升和转换
- [原创]c++整型提升(类型转换)
- C++常类型(const)
- 16位计算机中C++常用基本数据类型描述 和 字符常量 摘自 钱能C++教程
- C++常类型(const)
- Dev-C++下基本数据类型学习小结
- C/C++每日一课 >> [原创]细说如何确定一个变量的类型(2005-04-25)
- java中不同类型的转换和提升
- 明确C++风格的类型转换的用法
- symbian c++ 学习 2 数据类型及代码规范
- Dev-C++下关于几种int类型格式符的实验
- Dev-C++下关于float/double类型的实验
- 理解 《混沌 In C++::是类型?还是函数调用?》
- C++研究笔记(1)动态类型和静态类型
- C++类型中的转换--static_cast 和 reinterpret_cast