挑战408——组成原理(4)——强制类型转换

本来这部分内容考纲没有明确指出来的,但是往年的试题却是及其热门,可以出选择题,也可以出大题结合寄存器部分的知识考。所以这不仅仅可以看出一个人的语言功底,同时也可以看出对补码反码原码等的熟悉程度。
所以,在学习这个之前最好先回顾一下之前讲的内容,
挑战408——组成原理(2)——二进制数和十六进制数
挑战408——组成原理(3)——原码,补码,反码
好了言归正传,我们先来看看C语言中的基本数据类型(别问我为啥就强调C语言,你学这门课偏硬件):

基本数据类型
  1. 整型(int):即定点整数,在寄存器中一般用补码表示,其最高位代表符号位,一般是4个字节。具体的位数跟变异平台有关。
  2. 无符号整数(unsigned):无符号,即不考虑数据位,二进制码表示的数就是其值。一般用补码表示。
  3. 长整型和短整型(long short):用补码表示,这只是位数不同罢了(一个长一个短)。
  4. 单精度浮点数和双精度浮点数(float double):就是我们平时说的小数点会移动的小数,前面的32位,后面的是64位。

数据间的保留,当计算记过超出机器所能表示的范围的时候,就会发生“溢出现象”。此时面临一个问题,那么是丢掉前面的N位还是丢掉后面的N位呢?一般我们选择保留后面的N位,丢掉前面的N位,若丢掉后发现不能表示正确的结果,说明产生溢出,还有一种情况就是不受影响了。

十进制转二进制(代码)

在进入正题之前我们先介绍一下十进制跟二进制怎么转换(原谅我是个代码迷,就喜欢验证一下)。代码奉上:

#include <iostream>
#include <cstdlib> //引入这个头文件,使用itoa函数,因为这是C语言中的一个古老函数
#include <string>
using namespace std;
int main() {
	char array[64];
	int number = -4321;
	/*
     *itoa函数原型:char* itoa(int value,char *string,int radix)
	 *用法:将输入的数转换为相应进制的数,radix,对应的进制
	 */
	itoa(number,array,2);
	printf("integer = %d\n string = %s\n", number, array);
	return 0;
}

结果如下:
在这里插入图片描述
我用的是C++的环境编写的,有人可能会问,那为什么不用标准的COUT来呢?其实在精准度方面,C语言的printf函数确实是比C++做的好点。不信?那就试试下面这段代码。只是改变了一下输出的方式:

#include <iostream>
#include <cstdlib> //引入这个头文件,使用itoa函数,因为这是C语言中的一个古老函数
#include <string>
using namespace std;
int main() {
	char array[64];
	int number = -4321;
	/*
     *itoa函数,原型:char* itoa(int value,char *string,int radix)
	 *用法:将输入的数转换为相应进制的数,radix,对应的进制
	 */
	itoa(number,array,2);
	cout << "number = " << number << endl;
	for (int i = 0; i < 64; i++)
	{
		cout << array[i];
	}
	return 0;
}

那么会出现什么结果?自己去试试吧,话说到这里。

转换过程

同类型之间的转换

进入正题,先看下面的一段代码:

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	short x = -4321;
	unsigned short y = (unsigned short) x;
	printf("x = %d, y = %u\n",x,y);
}

结果如下:
在这里插入图片描述
我们前面说过,它们都是在寄存器中以补码的形式存放的,所以,我们把这两个数写成补码的方式(截取后16位):
在这里插入图片描述
我们惊奇的发现,这里的二进制表示居然一模一样。但是结果却不同,原因是X的第一位解释成了符号,而后面的才解释成为真值。(这里不知道有没有较真的人发现,-4321的补码没有错,但是61215的补码总觉得怪怪的?哈,肯定是不记得了正数的反码 = 补码 =原码,负数的才是取反后加一)。
所以,强制类型转换实际上是位值不变,只是改变了解释这些位的方式。

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	unsigned short x = 65535;
	short y = (short) x;
	printf("x = %d, y = %u\n",x,y);
}

同理分析这一段代码就一目了然了。

不同字节类型之间的转换

我们知道,不同类型的数据往往其占有的字节大小不一样,比如:
在这里插入图片描述

在结合上面的第一次的代码,-4321前面的16位都是1又是为何?不够的数都用1来凑?显然不对。

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	int x = 165537, u = -34991;
	short y = (short)x;
	short v = (short)u;
	printf("x = %d, y = %u\n",x,y);
	printf("u = %d, v = %u\n",u,v);
}

当数据太大,用二进制不好表示的时候我们选择用16进制(在之前提到过),分别是0x000286a1,0x86a1,0xffff7751, 0x7751,可以看出大字节转向小字节的转换的规则是:低位直接赋值(赋几位就看你的数据占几位,比如short占2字节,16位,一个16进制数代表4位2进制数),高位直接截断

那么显然,反过来,小字节转向大字节那就得扩展位数了。比如:

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	short x = -4321;
	int y = x;
	unsigned short u = (unsigned short)x;
	unsigned int v = u;
	printf("x = %d, y = %u\n",x,y);
	printf("u = %d, v = %u\n",u,v);
}

输出的数用16进制表示我就不说了,结论:从短字长到长字长的转换,相应的位值不变,向高位补充的数为符号位,所以-4321前面的16位都是1,因为它符号位是负号,如果是正号,那就变成0.

这部分内容考试必考,2分选择题左右。后面刷题的时候回再说

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值