C语言 (整型)数据的存储

一、数据类型介绍

前面我们已经学习了基本的内置类型:

char   //字符数据类型
short   //短整型
int   //整型
long   //长整型
long long   //更长的整型
float   //单精度浮点型
double   //双精度浮点型

以及它们所占用存储空间的大小。

类型的意义:

  1. 使用这个类型,则开辟规定大小的存储空间。
  2. 存储空间在内存中的定位。

二、类型的基本归类

整型家族:

char
	unsigned char //无符号char类型
	signed char
	
short
	unsigned short [int]
	signed short [int]
	
int
	unsigned int
	signed int
	
long
	unsigned long [int]
	signed long [int]

浮点数家族:

	float
	double

构造类型:

	数组类型
	结构体类型 struct
	枚举类型 enum
	联合类型 union

指针类型:

	int *pi;
	char *pc;
	float* pf;
	void* pv;

空类型:

	void 表示空类型
	通常应用于函数的返回类型、函数的参数、指针类型。

三、整型在内存中的存储

一个变量的创建是需要在内存中开辟空间存储的。
空间的大小是根据不同的类型而决定。

接下来我们谈谈数据是如何存储的
eg:

	int a = 20;
	int b = -10;

我们都知道 int 为 a 分配四个字节的空间。那么要如何存储?

3.1 原码、反码、补码

  1. 计算机中有符号数有三种表示方式,即原码、反码、补码。
  2. 三种表示方式均有符号位数值位两部分,符号位使用0表示“正”,用1表示“负”;而数值位三种表示方法各不相同。
  3. 原码:直接将数据翻译成二进制就可以。
  4. 反码:原码的符号位不变,其它位依次取反即可。
  5. 补码:反码+1可得到补码。
  6. 正数的原码、反码、补码都相同。

3.2 对于整型来说,数据在内存中存储的格式是补码。

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。

原因是,使用补码可以将符号位和数值域统一处理
同时,加法和减法也可以统一处理(CPU只有加法器)。
补码和原码相互转换,运算过程是相同的,都可以取反加一得到彼此。

我们也可以举个例子来证明:

在计算机中没有减法器,但是我们可以让正数加上负数,来进行减法操作。
	eg:1 + (-1)
	//1 正数原码、反码、补码相同
	//原码:00000000000000000000000000000001
	//反码:00000000000000000000000000000001
	//补码:00000000000000000000000000000001

	//-1
	//原码:10000000000000000000000000000001
	//反码:11111111111111111111111111111110
	//补码:11111111111111111111111111111111

我们观察原码,如果我们使用原码来进行 1+(-1) 会得到什么?
会得到 -2,这明显不是 1+(-1) 的结果。

如果我们使用补码来操作,结果就是 0。

四、大小端介绍

什么是大小端?

大端字节序
把数据的低位字节序的内容存放在高地址处,高位字节序的内容存放在低地址处。

小端字节序
把数据的低位字节序的内容存放在低地址处,高位字节序的内容存放在高地址处。

而数据到底是按照大端还是小端存储,要看编译器的设置。。。

那么如何用段代码来查看编译器是大端还是小端?

我们数值取一,然后取地址存储到指针类型char中。
我们只需要查看指针类型char中的第一个数据,是1则是小端字节序,是0则是大端字节序。
int main() {
	int a = 1;
	char* pi = (char*)&a;
	if (*pi == 1) {
		printf("小端\n");
	}
	else {
		printf("大端\n");
	}
	return 0;
}

也可以写成函数,进行优化…

int check_sys() {
	int a = 1;
	char* p = (char*)&a;
	return *p;
}

int main() {
	int ret = check_sys();
	if (ret == 1) {
		printf("小端\n");
	}
	else {
		printf("大端\n");
	}
	return 0;
}

五、来亿点练习题

①练习题

int main() {
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

答案:-1, -1, 255
解析
a,b,c 的补码都是一样的 1111 1111。
但是我们看待的不同,a 和 b 首位是符号位,1 表示是负数;而 c 是无符号整型,首位还是数据 1。
最后在输出时,%d是按照 int 形式输出,要整型提升,a 和 b 都是看符号位提升直接补齐 1;而 c 的整型提升因为没有符号位,直接补齐 0。导致最后结果不一样。

int main() {
	char a = -1;	//11111111
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	signed char b = -1;	//11111111
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	unsigned char c = -1;	//11111111
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	printf("a=%d,b=%d,c=%d", a, b, c);
	//整型提升
	//11111111111111111111111111111111 -> a,b
	//00000000000000000000000011111111 -> c
	return 0;
}

②练习题

int main() {
	char a = -128;
	printf("%u\n", a);
	return 0;
}

答案:4294967168
解析

int main() {
	char a = -128;
	//原码:10000000000000000000000010000000
	//反码:11111111111111111111111101111111
	//补码:11111111111111111111111110000000
	//char类型要截断:10000000

	printf("%u\n", a);
	//输出要整型提升,有符号char直接高位补1。
	//补码:11111111111111111111111110000000
	//要以 %u 无符号位方式打印,那么补码形式就是正数
	//正数原码反码补码都一致,系统就直接输出补码。
	return 0;
}

③练习题

int main() {
	char a = 128;
	printf("%u\n", a);
	return 0;
}

答案:4294967168
解析

int main() {
	char a = 128;
	//原码:00000000000000000000000010000000
	//反码:11111111111111111111111101111111
	//补码:11111111111111111111111110000000
	//char类型截断:10000000

	printf("%u\n", a);
	//有符号位整型提升,高位补1.
	//补码:11111111111111111111111110000000
	//%u 以无符号形式输出结果,补码原码一样
	//4294967168
	return 0;
}

char 类型内存存储。
127 再加 1 会变成 -128。
之后的 -127,-126都有迹可循,但是 -128 会复杂一些,需要查看补码反码原码。


④练习题

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

答案:-10
解析

int main() {
	int i = -20;
	//原码:10000000000000000000000000010100
	//反码:11111111111111111111111111101011
	//补码:11111111111111111111111111101100

	unsigned int j = 10;
	//原码:00000000000000000000000000001010
	//补码:00000000000000000000000000001010

	printf("%d\n", i + j);
	//11111111111111111111111111101100
	//00000000000000000000000000001010
	//11111111111111111111111111110110 - 结果补码
	//11111111111111111111111111110101
	//10000000000000000000000000001010 -> -10
	return 0;
}

⑤练习题

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

答案:死循环
解析

int main() {
	unsigned int i;  //无符号整型,没有负数
	//导致 i 永远大于等于 0
	for (i = 9; i >= 0; i--) {
		//%u 输出无符号整数
		printf("%u\n", i);
	}
	return 0;
}

⑥练习题

int main() {
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++) {
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}

答案:255
解析

int main() {
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++) {
		//-1 -2...-127 -128 127... 1 0 -1 -2 -3...-127 -128
		a[i] = -1 - i;
	}
	//strlen函数,找到0表示找到\0,\0表示结束
	printf("%d", strlen(a));
	//-1~-128=128
	//1~127=127
	//127+128=255
	return 0;
}

⑦练习题

unsigned char i = 0;
int main() {
	for (i = 0; i <= 255; i++) {
		printf("hello world\n");
	}
	return 0;
}

答案:死循环
解析

unsigned char i = 0;
int main() {
	//无符号char类型,最高范围只能到255
	//始终小于等于255,导致for循环死循环
	for (i = 0; i <= 255; i++) {
		printf("hello world\n");
	}
	return 0;
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值