2.2.3 C语言中的整数类型及类型转换(为什么强制类型转换值发生改变?带你从机器码的角度分析)


首先看一下c语言整数数据类型范围

注意:数值范围没有负数的则为无符号位的数,有负数范围的则为有符号位的数
在这里插入图片描述

输出时:
%u无符号十进制整数
%d有符号十进制整数
%0无符号八进制
%x无符号十六进制整数
在计算机中数据都是以补码形式存储的,%u无符号输出,没有符号位,是正数;%d有符号输出,有符号位,符号位在最高位

1.有符号数和无符号数的转换(相同字长)

  • 我们在C语言中常利用强制类型转换,有时候强制类型转换的结果却不是我们希望得到的,因为计算机存储数据是以补码形式存储的。
  • 有时候强制类型转换可能会改变数值,可能是数据类型有无符号位导致的。
  • 无符号位是正数就不用转换,因为正数原码=补码
  • 有符号位的数,根据符号位是0还是1来判断是否需要转换,那么如果符号位是1,是负数就要转换,数值当然会不同。
  • 现在我们看一段代码来看一下这种特殊情况:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
	short x=-4321;
	unsigned short y=(unsigned short)x;
	printf("x=%d,y=%u\n",x,y);
	return 0;
}

在这里插入图片描述

  • 我们可以看出y值和x值没有一点关系,咱们将其都转换成二进制,我们便知道了为什么。且看二进制转换表;
    在这里插入图片描述
    我在自己的电脑上测试了一下,由于电脑是64位,所以转换就是64个二进制数,至于为什么16位往左所有数都是1,这就涉及到了符号扩展,详情可参考我之前的一篇文章符号扩展
    在这里插入图片描述
  • 去掉符号位补码转原码为下图所示:
    在这里插入图片描述
    在这里插入图片描述
  • 其中x为补码,y为无符号二进制真值,正数的补码=原码。因为数在计算机中都是以补码形式存储的,正数的补码是自身,负数的补码需要转换,具体转换参考原码、反码、补码、移码转换规则
  • unsigned short 为无符号整数,所以它没有符号位,全是数值位,是正数。
  • 而short是有符号的整数,有符号位,符号位在最高位,需要将补码转换成原码输出。
  • 可以看出,强制类型转换结果相应位置的值不变,仅仅只改变了解释这些位的方式,是short解释,还是unsigned short 解释,这两种方式。

同样的我们再看一段代码仔细揣摩揣摩:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
	unsigned short x=65535;
	short y=(short)x;
	printf("x=%u,y=%d\n",x,y);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 相应位置数值相等,但是表示结果不同,那是因为解释方式不同;unsigned short 和short两种解释 方式。

2.不同字长整数之间的转换

(1)大字长变量向小字长变量强制类型转换

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
	int x=165537,u=-34991;  //int 4B  
	short y=(short)x,v=(short)u; // short 2B
	printf("x=%d,y=%d\n",x,y);   
	printf("u=%d,v=%d\n",u,v);
	return 0;
}

在这里插入图片描述

  • 当大字长变量向小字长变量强制类型转换时,系统将多余的高位字长部分直接截断舍去,低位直接赋值
    在这里插入图片描述

(2)小字长变量向大字长变量强制类型转换

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
	short x=-4321; // short 2B
	int y=x; //	int 4B
	unsigned short u=(unsigned short)x;
	unsigned int v=u;
	printf("x=%d,y=%d\n",x,y);   
	printf("u=%u,v=%u\n",u,v);
	return 0;
}

在这里插入图片描述

  • 这里我们转换成十六进制输出
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
	short x=-4321; // short 2B
	int y=x; //	int 4B
	unsigned short u=(unsigned short)x;//无符号数,直接取当前数据类型长度的原数字x的补码长度,不用转换成原码输出
	unsigned int v=u;
	printf("x=%d,y=%d\n",x,y);   
	printf("u=%x,v=%u\x",u,v);
	return 0;
}

在这里插入图片描述

  • 我们发现,短字长整数到长字长整数的转换,不仅要使相应的位置相等,高位部分还会扩展为原数字的符号位
  • 注意:char类型为8位ASCII码整数,转换成int型时,高位部分补0即可。ASCII码由7位二进制数字组成。
发布了36 篇原创文章 · 获赞 5 · 访问量 3519

猜你喜欢

转载自blog.csdn.net/weixin_43914604/article/details/104281768