深度剖析数据在内存中的存储

Debug和release版本的区别

release版本会自动优化程序,比如上图中将变量i放到低地址存储防止数组溢栈造成死循环。


1. 数据类型介绍

 类型的意义:
1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
2. 如何看待内存空间的视角。


1.1 类型的基本归类:

整形家族:

 注意:如果只写char,到底是signed char还是unsingned char是未定义的,取决于编译器的实现。其他的如果只写基本类型则是属于signed类型。

浮点数家族:

构造类型:

//第一个void 表示函数不会返回值
//第二个void 表示函数不需要传任何参数
void test(void)
{
	printf("hehe\n");
}
int main()
{
	test();
	return 0;
}


2. 整形在内存中的存储

数值有不同表示形式                                                        eg             

(1)2进制                                                                           0b10101

(2)8进制                                                                            025

(3)10进制                                                                          21

(4)16进制                                                                          0x15


2.1 原码、反码、补码

整数的2进制表示也有三种表示形式:

1. 正的整数,原码、反码、补码相同

 2. 负的整数,原码、反码、补码是需要计算的

三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位
正数的原、反、补码都相同。

原码:直接通过正负的形式写出的二进制序列就是原码

反码:原码的符号位不变,其他位按位取反得到的就是反码

补码:反码+1就是补码

             故得出结论整数内存中存放是补码的二进制序列


2.2 大小端介绍

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址
中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地
址中。


3.练习

1.请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

 判断字节序是小端或者大端只需检测首元素地址是00还是01,如上图。

而要去出十六进制首元素地址,需要步骤:

(1)&a---->int*

(2)*&a---->整形字符中的四个字节

(3)*(char*)&a------>强制转换类型为char*则取出一个字节的内容

#include <stdio.h>
int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
}

2.输出什么?

#include <stdio.h>
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;
}

 首先

signed char   

因第一个比特位的二进制数字表示符号,则只有7比特位的数字

从00000000到01111111都是正数计算出来的十进制数就是0到127.

而从10000000到11111111都是负数   注意:10000000直接计算成-128

从10000000到11111111计算出来的十进制数就是-128到-1.

unsigned char

00000000到11111111计算出来的十进制数就是0-255

注意:(1)signed发生整型提升补的是符号位数字,而unsigned发生整型提升补的是0.

           (2)由四个字节转换为一个字节时发生截断,直接从右端截取8个比特位并使用。


4.例题分析

(1)

#include <stdio.h>
//
//int main()
//{
//	//char -128~127
//	char a = -128;
//
//	//10000000000000000000000010000000
//	//11111111111111111111111101111111
//	//11111111111111111111111110000000 - 截断
//	//10000000 - a
//	//11111111111111111111111110000000 - 提升
//	//
//	printf("%u\n", a);
//	printf("%d\n", a);
//	//11111111111111111111111110000000
//	//10000000000000000000000001111111
//	//10000000000000000000000010000000
//	//-128
//
//	//
//	//
//	//%u - 打印无符号整数
//	//
//	return 0;
//}
//

//#include <stdio.h>
//int main()
//{
//	//-128~127
//	char a = 128;
//	//00000000000000000000000010000000
//	//10000000 - a
//	printf("%u\n", a);
//	printf("%d\n", a);//-128
//
//	//10000000
//	//11111111111111111111111110000000
//	//10000000000000000000000001111111
//	//10000000000000000000000010000000
//
//	return 0;
//}

(2)

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

(3)

int main()
{
	char a[1000];
	int i;

for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	//arr[i] --> char   -128~127
	//-1 -2 -3 -4 ... -1000
	//-1 -2 ... -128 127 126 125 .. 3 2 1 0 -1 ...
	//128+127 = 255
	printf("%d", strlen(a));//255
	//strlen 是求字符串的长度,关注的是字符串中'\0'(数字0)之前出现多少字符

	return 0;
}

注意:char类型变量存储范围是从-128~127.

(4)

#include <stdio.h>
unsigned char i = 0;
unsigned char 类型的取值范围是0~255

int main()
{
	for (i = 0; i <= 255; i++)//因为char类型取值范围是0~255而i<=255恒成立,所以就死循环了。
	{
		printf("hello world\n");
	}
	return 0;
}

(6)

int main()
{
	//int len = strlen("abcdef");
	//printf("%d\n", len);
	//size_t -> unsigned int
	//
	if ((int)strlen("abc") - (int)strlen("abcdef")>0)
		printf(">\n");
	else
		printf("<\n");

	return 0;
}

输出结果为(int)strlen("abc")-(int)strlen("abcdef")>0    因为strlen是size_t类型属于无符号数,无符号数-无符号数也是一个无符号数,而无符号数>0。


5.计算

//int main()
//{
//	int i = -20;
//	//10000000000000000000000000010100
//	//11111111111111111111111111101011
//	//11111111111111111111111111101100 - -20的补码
//	//
//	unsigned int j = 10;
//	//00000000000000000000000000001010
//	printf("%d\n", i + j);
//	//11111111111111111111111111101100
//	//00000000000000000000000000001010
//	//11111111111111111111111111110110 - 补码
//	//10000000000000000000000000001001
//	//10000000000000000000000000001010 -> -10
//	//
//	return 0;
//}

注意:计算的时候是用补码进行计算。两个0相加是0,两个1相加余0进1,一个1一个0相加是1.
 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值