文章目录
- 问题发现
- 什么是无符号整形
- 补码的计算
- 无符号整形的输出
- 正确时:
- 错误时:
- 问题解决
- int用%d和%u输出
- unsigned int用%d和%u输出
问题发现
近日在练习过程中发现无符号整形数如果赋值为“-1”可以用%d进行输出,从而得到问题
代码如下
#include<stdio.h>
int main()
{
unsigned int e = -1; //输出结果是-1,说明这里无符号整形也能储存-1,问题不明
printf("unsigned int=%d\n",e);
return 0;
}
结果如下:
unsigned int=-1
什么是无符号整形
在书中说明整形为 int 无符号整形为 unsigned int
int在储存数据空间中最高位代表数据的正负(0为正,1为负)
unsigned int 在储存中所有数据空间皆为数据值,但只能存放正数。
所以可以存放的正数范围比整形变量大一倍
例如int空间为4个字节,所以unsigned int 也为4个字节,但第一位可以表示数据而不是符号。则有以下补码:
int a =1:
00000000 | 00000000 | 00000000 | 00000001 |
int b =-1:
10000000 | 00000000 | 00000000 | 00000001 |
最大值int max = 2147483647 (231-1)
01111111 | 11111111 | 11111111 | 11111111 |
最大值unsigned int Max = 4294967295 (232-1)
11111111 | 11111111 | 11111111 | 11111111 |
补码的计算
正整数的补码是其二进制表示,与原码相同
例:+9的补码是00001001。(备注:这个+9的补码是用8位2进制来表示的,补码表示方式很多,还有16位二进制补码表示形式,以及32位二进制补码表示形式,64位进制补码表示形式等。每一种补码表示形式都只能表示有限的数字。)
求负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1 。
同一个数字在不同的补码表示形式中是不同的。
比如-15的补码,在8位二进制中是11110001,然而在16位二进制补码表示中,就是1111111111110001。以下都使用8位2进制来表示。
例:求-5的补码。
-5对应正数5(00000101)→所有位取反(11111010)→加1(11111011)
所以-5的补码是11111011。
无符号整形的输出
无符号整形在输出时要用%u格式来进行输出(十进制无符号数),若赋值为负值则会输出错误(如int类型负数)
例如:
正确时:
unsigned int a = 30;
printf("unsigned int=%u\n",a);
输出为
30
错误时:
unsigned int a = -30;
printf("unsigned int=%u\n",a);
输出为
4294967266
问题解决
int用%d和%u输出
在查阅资料后发现,C中%d与%u的区别是程序如何去解释这一变量的数据
所以,%d在解释过程中第一位数据代表了符号,%u第一位数据代表了数据值
在输出一下数据时就有:
int a = -1;
printf("%d\n%u",a);
-1
4294967295
因为-1的补码为
11111111 | 11111111 | 11111111 | 11111111 |
%d解释过程:
1.第一位是1,所以为负值。
2.由补码再求补码,得到以下补码
10000000 | 00000000 | 00000000 | 00000001 |
3.输出结果 -1
%u解释过程:
直接将其按源码处理,所以值为232-1 = 4294967295
unsigned int用%d和%u输出
经过上面的讨论,有如下代码
unsigned int a = -1;
printf("%d\n%u",a);
输出为
-1
4294967295
同理,在赋值时,-1的源码被转换为补码:
11111111 | 11111111 | 11111111 | 11111111 |
所以在赋值到unsigned int 中时也是相同的,所以在经过%d%u解释后输出的值仍为-1 和 4294967295。其他负数值同理。