C语言类型转换和负数的无符号输出
创始人
2025-05-30 12:40:48
0

1.类型转换的相关概念
(1)类型转换分类:自动类型转换(简称“自转”)和强制类型转换(简称“强转”)。
(1)类型提升:编译器对操作数进行运算前,将所有操作数都转换成取值范围较大的操作数类型。
(1)类型提升目的:避免数据信息丢失。因为由于级别高的数据类型比级别低的数据类型所占的内存空间大,可以保持数据类型的精度。
(1)整数提升:char型和short型进行运算前都自动提升为int型,C99和C11中还可以产生向unsigned int型的转换。
(1)类型提升规则:根据操作数类型由低到高进行转换。如图所示,箭头方向表示转换方向,纵向箭头表示必然转换,横向箭头仅表示转换方向不表示转换过程。

一个int型操作数与一个float型操作数进行算数运算,编译器会先将int型直接转换成float型,无需经过int型先转换为unsigned int型再转换为long型的中间过程。
特例:如果一个操作数是long型,另一个是unsigned int型,同时unsigned int型操作数的值又不能用long型表示,则两个操作数都转换为unsigned long型。

1.类型转换的几种情况
()赋值中的自动类型转换:赋值运算符左侧(目标侧)变量的类型和右侧表达式的类型不一致,则右侧表达式的值自动转换成左侧变量的类型。
比如:int n = 2; float f = 3.5; double d = n+f,编译器运算n+f时,会将变量n的类型提升为变量f相同的float型,n+f为变量d赋值时,会将float型的运算结果自动转换为double型再赋值给d。
()高数据类型转换低数据类型:可能丢失信息,比如:int转char会丢失高24位,float转int会丢失小数部分(在某些情况下整数部分的精度也会丢失),double转float会丢失小数部分精度(四舍五入)。
()低数据类型转换高数据类型:改变数据形式,不会丢失信息。
()无符号数据类型(unsigned型)和有符号数据类型(signed型)之间的转换
①unsigned和signed都只能定义整型数据(short,int,long)和字符型数据(char型可以看成特殊的int型),所以unsigned型和signed型之间的转换只针对整型数据。
②unsigned型转换为其他类型数据:转换为同字节数据类型时不改变数据内容,转换为低字节数据类型时截取低字节内容,转换为高字节数据类型时高位补0。
③signed型转换为其他类型数据:转换为同字节数据类型时不改变数据内容,转换为低字节数据类型时截取低字节内容,转换为高字节数据类型时补符号位(负数高位补1,非负数高位补0)。
④unsigned型和signed型转换数据类型时,数据变化只与字节大小有关,和目标数据类型无关。
以short型和unsigned short型为例,代码如下。

/*short型*/
int main(int argc, const char *argv[])
{char a0 = 0;unsigned char a1 = 0;short b0 = 0;unsigned short b1 = 0;int c0 = 0;unsigned int c1 = 0;b0 = -1;                     /*负数在内存中用二进制补码存储,-1的补码1111 1111 1111 1111*/b1 = (unsigned short)b0;     /*转换为同字节数据类型unsigned short时不改变数据内容*/a0 = (char)b0;               /*转换为低字节数据类型char时截取低8位内容*/a1 = (unsigned char)b0;      /*转换为低字节数据类型unsigned char时截取低8位内容*/c0 = (int)b0;                /*转换为高字节数据类型int时负数高位补1*/c1 = (unsigned int)b0;       /*转换为高字节数据类型unsigned int时负数高位补1*/printf("char:%d\n", a0);printf("unsigned char:%u\n", a1);printf("short:%d\n", b0);printf("unsigned short:%u\n", b1);printf("int:%d\n", c0);printf("unsigned int:%u\n", c1);return 0;
}/*unsigned short型*/
int main(int argc, const char *argv[])
{char a0 = 0;unsigned char a1 = 0;short b0 = 0;unsigned short b1 = 0;int c0 = 0;unsigned int c1 = 0;b1 = 65535;                  /*无符号数65535的原码1111 1111 1111 1111*/b0 = (short)b1;              /*转换为同字节数据类型short时不改变数据内容*/a0 = (char)b0;               /*转换为低字节数据类型char时截取低8位内容*/a1 = (unsigned char)b0;      /*转换为低字节数据类型unsigned char时截取低8位内容*/c0 = (int)b0;                /*转换为高字节数据类型int时高位补0*/c1 = (unsigned int)b0;       /*转换为高字节数据类型unsigned int时高位补0*/printf("char:%d\n", a0);printf("unsigned char:%u\n", a1);printf("short:%d\n", b0);printf("unsigned short:%u\n", b1);printf("int:%d\n", c0);printf("unsigned int:%u\n", c1);return 0;
}

两段代码运行结果相同,如图所示。

1.负数的无符号输出
()定义char a0= -1,测试a0的无符号输出内容,代码如下。

int main(int argc, const char *argv[])
{char a0 = -1;printf("a0-d:%d\n", a0);printf("a0-u:%u\n", a0);return 0;
}

运行结果如图所示。

因为负数是在内存中以补码的形式存储,a0变量存储的二进制数据是1111 1111,也就是无符号数255,所以a0的%u输出应该是255(即2^8-1),然而运行结果是4294967295(即2^32-1)。
之所以出现这个输出结果,和printf函数以及类型转换的方式有关系。当使用printf进行打印时,printf会在内存中分配一段buffer用于存储打印的内容,该段buffer以4个字节为一个单位存储数据,所以当char型变量a0的值传入printf函数后,会自动进行类型提升,从1字节数据提升为4字节数据。根据类型提升的规则,1字节数据-1转为4字节数据时,会补符号位1,因此printf缓存中存储的二进制数据为1111 1111 1111 1111 1111 1111 1111 1111,用%d打印这段数据是-1,用%u打印这段数据是4294967295,而不是255。
如果想要用%u打印a0的内容,需要将a0进行类型转换,推荐使用强转,代码如下。

int main(int argc, const char *argv[])
{char a0 = -1;printf("a0-d:%d\n", a0);printf("a0-u:%u\n", (unsigned char)a0); /*以无符号格式输入a0*/return 0;
}

运行结果如图所示。

()同理,定义short b0= -1,printf用%d打印这段数据是-1,用%u打印这段数据是4294967295,而不是65535(即2^16-1),如果想要用%u打印b0的内容也需要进行类型转换。
()此外,某些编译器下unsigned char a1= -1不会提示warning也不会报错,因为负数是在内存中以补码的形式存储,所以可以看作a1变量存储的是无符号数据255。

4.其他
(1)关于printf函数读写缓存的方式,代码如下。

int main(int argc, const char *argv[])
{int num0 = 0;int num1 = 0;int num2 = 0;float dec0 = 0;num0 = 1;num1 = 2;num2 = 3;dec0 = 9.8;printf("float byte:%d, int byte:%d\n", sizeof(float), sizeof(int));printf("%f, %d, %d, %d\n", dec0, num0, num1, num2);printf("%d, %d, %d, %d\n", dec0, num0, num1, num2);printf("%d, %d, %d, %d\n", num0, dec0, num1, num2);return 0;
}

在32位编译器下运行这段代码,结果如图。

 在64位编译器下运行这段代码,结果如图。

 我们

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...