目录
通过前几天对内存中内数据的存储的学习,特地总结一下。
1.数据的类型
2.整形在内存中的存储
我们知道变量的创建是要在内存中开辟地址空间的,而空间的大小是由不同的数据类型决定的。那数据在内存中又是如何存储的呢?
2.1 原码 反码 补码
我们知道整形在内存中是以补码(二进制)形式存储的
正数的原码,反码,补码都一样。
例如 int a = 1 原码 00000000 00000000 00000000 00000001
反码 00000000 00000000 00000000 00000001
补码 00000000 00000000 00000000 00000001
负数的补码则要经过除除符号位外全部取反得到反码,再在反码的基础上加1,最终得到补码。
l例如int a = -1 原码 10000000 00000000 00000000 00000001
反码 111111111 111111111 111111111 111111110
补码 111111111 111111111 111111111 111111111
我们进入到内存中去看,如果你用的是VS编译器,可根据下面的步骤看:
#include<stdio.h>
int main() {
int a = 10;
int b = 20;
return 0;
}
上面是一段简单的代码,我们进行调试。按ctrl+F11或F11进入调试。
然后继续 ctrl+F11或F11,直到箭头到达return 0。
再按下面的操作找到内存。
再分别输入&a按回车键,&b按回车键
VS内存中的数据是以16进制展现给我们。
我们不难得出a = 10 10的16进制为 00 00 00 0a
b = 20 20的16进制为 00 00 00 14
通过与上面内存中展示出来的相比较,老感觉顺序很别扭。通过查询,发现这与大端小端有关。
2.2 大端小端
什么是大端小端?
大端 数据的字节序在内存中是 低位存放在高地址中,高位存放在低地址中
小端 数据在内存中在内存中是 低位存放在低地址中,高位存放在高地址中
根据网上资料,大端存储还是小端存储,这与编译器有关,如果想知道我们使用的编译器是以大端存储还是小端存储,我们可以写一段程序来实现。这里我选择用1,也可以用其他数。
低 高
若小端 01 00 00 00
若大端 00 00 00 01
#include<stdio.h>
int main() {
int a = 1;
char* p = &a;
if (*p == 1) printf("小端");
else printf("大端");
return 0;
}
3.存储实例
我们举一些代码例子,以便更深入的理解。
3.1整形范围
通过代码查询变量取值范围
#include<stdio.h>
#include<limits.h>
int main() {
INT_MAX;
return 0;
}
鼠标指到INT_MAX,右键点击,再点击转到定义。
3.2 有符号整形 无符号整形
int a = 1; 有符号整形
unsigned int a = 1; 无符号整形
下面一段代码,输出什么?
#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;
}
我的理解:
//#include<stdio.h>
//int main() {
//
// //因为-1是一个整形数int 放在char里会发生截断
// //11111111 11111111 11111111 11111111 (-1的补码)
// //11111111 (对补码进行截断,截断了后八位)
// char a = -1;
// //11111111
//
// signed char b = -1;
// //11111111
//
// unsigned char c = -1;
// //无符号位时,截断后高位补0
// //11111111
// //00000000 00000000 00000000 11111111 高位补0后的值 255 最高位为0,表示正值 即无符号
// printf("%u %d %d",a,b,c); //最终输出 -1 -1 255
//
//
// return 0;
//}
下面两段代码输出什么?
//1
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
//2
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
%u为打印整形 无符号输出十进制数
原因:
//#include<stdio.h>
//int main() {
//
//char a = -128;
10000000 00000000 00000000 10000000 -128的原码
11111111 11111111 11111111 01111111 -128的反码
11111111 11111111 11111111 10000000 -128的补码
10000000 因为 a为char型 所以对-128的补码进行截断
11111111 11111111 11111111 10000000 整形提升 由于符号位为1 故高位补位时全补1
// 整形提升 高位补0还是1 取决于截断后的最高符号位
//
//char a1 = 128;
//printf("%u %u",a,a1); //%u 打印整形(故需要整形提升) 无符号输出十进制数
// return 0;
//}
3.3数据存储的特点
我们试着运行下面几段代码:
#include<stdio.h>
int main(){
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
return 0;
}
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
一般情况下,我们会以为第一个代码从9输出到0就截止,第二个打印256个hello world就停了,可真的是这样吗?
通过运行
通过运行,居然是个死循环。
为了便于观察,我们加点代码:
#include<stdio.h>
#include<windows.h>
int main() {
unsigned int i;
for (i = 9; i >= 0;i--) {
printf("%u\n",i);
Sleep(1000);
}
return 0;
}
运行如下:
从9到0我们不难理解,可0之后又变成4294967295这个数又是咋来的呢?
通过观察,我们知道变量 i 是一个无符号整形,即i的取值范围为0到一个很大的数,故i永远也不会取负数,所以会死循环,当减为-1时
原码 10000000 00000000 00000000 00000001
反码 111111111 111111111 111111111 111111110
补码 111111111 111111111 111111111 111111111
又因为%u为输出无符号十进制数,所以
4294967295 就是 111111111 111111111 111111111 111111111
若把%u换成%d呢
0后又跟-1?
这是因为%d输出有符号十进制数,故 此时111111111 111111111 111111111 111111111为-1的补码了
补码 111111111 111111111 111111111 111111111
反码 111111111 111111111 111111111 111111110
原码 10000000 00000000 00000000 00000001
通过以上,我们得出一个规律:循环
如上图所示,char型无符号时,0减1的值为255,255加1的值为0 即0---255为一个循环。
char型有符号时,127加1的值为-128,-128减1的值为127 即-128---127为一个循环。