C语言之关键字(3)

signed/unsigned关键字

整数在内存的存储

数据存储不仅要关注原反补,还要关注大小端

有符号整数(signed) VS 无符号整数(unsigned)


char:
	unsigned char;
	signed char;

short:
	unsigned short[int];
	signed short[int];

int:
	unsigned int;
	signed int;

long:
	unsigned long[int];
	signed long[int];
	

原反补

之前的两节中讲过一个变量的创建是要在内存中开辟空间的,空间的大小是根据不同的类型而决定的。那么,数据在所开辟内存中到底是如何存储的呢?

  • 有符号数
	int a=20;
	int b=-10;

我们知道,编译器为a变量分配了四个字节的空间,那如何存储呢?

首先,对于有符号数,一定要能表示该数据是正数还是负数,所以我们一般用最高比特位来进行充当符号位。

其次,计算机中的有符号数有三种表示方式,即 原码,反码,补码
①任何数据在计算机中都必须被转化成二进制(因为计算机只认识二进制数字);
②三种表示方式均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方式各不相同;
③如果数据是一个正数,那么它的原反补都相同;
④如果数据是一个负数,那么就要遵循下面的规则进行转化:
原码:直接将二进制按照正负数的形式翻译成二进制就可以。
反码:将原码的符号位不变,其他位依次按位取反就可以得到了。
补码:反码+1(符号位要参与运算) 整型数据存放在内存中其实存放的是补码在这里插入图片描述

  • 无符号数:不需要转化,也不需要符号位,原反补相同
  • 对于整数来说:数据存放内存种蘑菇其实存放的是补码
    !为什么都是补码呢?
    ①使用补码,可以将符号位和数值域统一处理
    ②加分和减法可以统一处理(CPU只有加法器)
    ③补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

样例

//字面值转补码
int a=20;
//20是正整数,原反补相同
//0000 0000 0000 0000 0000 0000 0001 0100 

int b=-10;
//-10是负整数
//原码:1000 0000 0000 0000 0000 0000 0000 1010
//反码:1111 1111 1111 1111 1111 1111 1111 0101
//补码:1111 1111 1111 1111 1111 1111 1111 0110

补码转原码
方法一:先-1,再符号位不变,其他位按位取反
方法二:取反+1 (将原码到补码的过程再来一遍)计算机硬件完成原反补的转化,这样的方法可以用一条硬件电路完成转化

unsigned int a=-10;
//这样的代码不会报错,也没有任何提示,这是为什么呢?
//这个步骤是定义变量并初始化。在这个过程中是先有空间再有内容:1.整型存储的时候,空间是不关心的内容的,只提供存储的空间;2.在将数据保存在空间的时候,数据已经转化为二进制,而并没有关注变量本身的类型;3.变量本身的类型只在读取的时候具有意义。

深入理解变量内容的存入与取出

  1. :字面数据必须先转成补码,在放入空间当中。所以,所谓符号位,完全看数据本身是否携带±号,和变量类型是否有符号无关
  2. :取数据一定要先看变量本身类型,然后才决定要不要看最高符号位。如果不需要,直接二进制转成十进制。如果需要,则需要转成原码,然后才能识别(但是最高符号位在哪里,又要明确大小端)

大小端

在这里插入图片描述

  1. 计算机/内存硬件厂商决定大小端(一般都是小端,很少使用大端)
  2. CPU访问的基本单元为字节
  3. 数据按照字节,是有高权值位和低权值位之分的;内存按照字节也是有高地址和低地址之分的
  4. 大端: 按照字节为单位,低权值位数据存储在高地址处
    小端: 按照字节为单位,低权值位数据存储在地地址处
    口诀:小小小(权值,地址,存储方案)(权值位比较小,地址数字比较小,则为小端)在这里插入图片描述

整形取值范围

  1. 数据表示范围的实质: 所谓特定的数据类型,能表示的数据取值范围,取决于多位比特位形成的排列组合的个数
//我们以char为列

unsigned char[0,2^8-1]
signed char:[-2^7,2^7-1]//char等价

那么对于有符号的字符来说,0有+0和-0之分,两个的二进制分别表示为 0000 0000、1000 0000。但是计算机只会将前者解读为0,而后者会被解读为-128,那么如何理解呢?
在这里插入图片描述
2. 总结规律: 整数的取值范围
无符号:[0,2^n-1]
有符号:[-2^(n-1), 2^(n-1)-1]

有关符号位的练习题

#include <stdio.h>
#include <windows.h>

int main()
{
	char a[1000];
	int i;
	for(i=0; i<1000; i++)
	{
		a[i]=-1-i; 
	}
	printf("%d",strlen(a)); //strlen介绍,字符串认识,\0的认识(字符串结束标志,char中占一个字节,即为字符'0',不算在strlen里面)
	return 0;

在这里插入图片描述
a[0]=-1 , a[1]=-2 … a[127]=-128 a[128]=127 … a[255]=0
(遇到字符0停止)因为0-255有256个数字,所以字符串的长度为256-1=255

#include <stdio.h>
#include <windows.h>

int main()
{
	int i= -20;
	unsigned int j = 10;
	printf("%d\n", i+j);

	return 0;
}

-20:
原:1000 0000 0000 0000 0000 0000 0001 0100
反:1111 1111 1111 1111 1111 1111 1110 1011
补:1111 1111 1111 1111 1111 1111 1110 1100

10:
原反补:0000 0000 0000 0000 0000 0000 0000 1010

-20+10:
1111 1111 1111 1111 1111 1111 1110 1100
0000 0000 0000 0000 0000 0000 0000 1010

补:1111 1111 1111 1111 1111 1111 1111 0110
而%d——有符号整数类型(%u-无符号整数类型)
原:1000 0000 0000 0000 0000 0000 0000 1010=-10

#include <stdio.h>
#include <windows.h>

 int main()
{
	unsigned int i;
	for (i = 0; i >= 0; i++)
	{
		printf("%u\n", i);
	}
	system("pause");
	return 0;
}

%u为无符号整数:
i最大值的二进制补码为:
1111 1111 1111 1111 1111 1111 1111 1111
当i最大值+1时,二进制补码为:
1 0000 0000 0000 0000 0000 0000 0000 0000
但又因为unsigned int是四个字节 (32比特位),所以会发生截断,即为:
0000 0000 0000 0000 0000 0000 0000 0000
i又变为0,而之后一旦i加到最大值后再+1,又会变为0,无限循环。
所以这道题是一个死循环

那么最后再留一道思考题:

#include <stdio.h>
#include <windows.h>

 int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}
	system("pause");
	return 0;
}
  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值