首页 > 系统相关 >【提升C语言基础知识】数据在内存中的存储

【提升C语言基础知识】数据在内存中的存储

时间:2024-03-16 20:58:39浏览次数:16  
标签:存储 字节 int 浮点数 补码 基础知识 char 内存 C语言

1.整数在内存中的存储

1.1 原码,反码,补码

整数(占4个字节,即32个bit)的二进制表示方法有3种,即原码,反码,补码,三种表示方法均有符号位数值位两部分

原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码

反码:将原码符号位最高位,0为正,1为负不变,其余位按位取反得到反码

补码反码+1得到补码 (补码得到原码也可以使用 取反,+1 的操作)

正整数的原,反,补码都相同,如下

int a = 10;
//00000000000000000000000000001010 - 原码
//00000000000000000000000000001010 - 反码
//00000000000000000000000000001010 - 补码

负整数的原,反,补码各不相同,如下

int b = -10;
//10000000000000000000000000001010 - 原码
//11111111111111111111111111110101 - 反码
//11111111111111111111111111110110 - 补码

对于整型来说:数据存放内存中其实存放的是二进制的补码

1.2 大小端问题

我们设置一个整型的n的地址为 0x11223344 

#include <stdio.h>
int main()
{
	int n = 0x11223344;//两个16进制位表示8个2进制位
	return 0;
}

 当调试查看内存的存放的时候,发现地址存放顺序是反的,为 44 33 22 11,我们需要注意:

1.数据在内存中储存的是二进制的补码

2.在调试窗口观察时,为方便显示,显示的是16进制

3.存放顺序是倒着的

1.2.1大小端字节序存储(以字节讨论)

我们上面的地址 0x11223344  可以看成 0x 11 22 33 44 ,在10进制中比如123这个数 ,3是个位,2是十位,1是百位,右边是低位,左边是高位,可以理解为右边是小端,左边是大端,在16进制中也一样,44是低位,11是高位

大端字节序存储:把一个数据的低位字节的内容储存到高地址处,把高位字节的内容储存到低地址处

小端字节序存储:把一个数据的低位字节的内容储存到低地址处,把高位字节的内容储存到高地址处

所以当前存储方式为 小端字节序存储

1.3 相关练习

练习1

设计一个程序判断当前机器的字节序

参考答案

#include <stdio.h>
int main()
{
	int a = 1;
	if (*(char*)&a == 1)  // &a :01 00 00 00
		printf("小端"); 
	else                  // &a :00 00 00 01
		printf("大端"); 
	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);
}

答案

a=-1, b=-1, c=255

解析

char类型占1个字节,就是8个bit位,取的是后8位;

signed char是有符号char,最高位是符号位,其余7位是数值位,正号补码范围是00000000(0)~01111111(127),负号补码范围是10000000(-128)~11111111(-1),为了不浪费数据,补码为10000000的默认为是-128,所以 signed char的取值范围是-128~127; unsigned char是无符号char,所有位都是数值位,从00000000(0)~11111111(255),所以unsigned char的取值范围是0~255;

用%d打印,类型需要提升为整型,signd补齐高位时看符号位,符号位是1补1,是0补0,unsignd全补0

练习3

下面程序结果是什么?

#include <stdio.h>
int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
}

答案

255

解析

strlen计算的是‘\0’之前的元素个数,'\0'的ASCII码值是0;

2. 浮点数在内存中的存储

任意一个二进制浮点数V都可以表示成下面的形式:

 比如

所以浮点数的存储其实存的是S,M,E相关的值

对于32位的浮点数(float),最高1位存储符号位S,后8位存储指数E,剩下的23位存储有效数字M 

对于64位的浮点数(double),最高1位存储符号位S,后11位存储指数E,剩下的52位存储有效数字M 

 2.1 浮点数存的过程

有效数字M

因为1\leq M< 2,所以M可以写成1.xxxxxxde形式,其中xxxxxx表示小数部分

在计算机内部保存M时,默认这个数的第一位总是1,因此可以舍去,只保留后面的xxxxxx部分,如,保存1.01时,只保存小数点后的01,等读取时再把小数点前的1加上, 这样做的目的是节省1位有效数字,以32位浮点型为例,留23位保存M,将第一位舍去后,等于可以保留24位有效数字

指数E

E为一个无符号整数(unsigned int),这意味着,如果E为8位,它的取值范围为0~255,如果E为11位,范围是0~2047,但是科学计数法中E是可以出现负数的,所以规定存入内存时E的真实值必须加上一个中间值,对于8位E,这个中间值是127,对于11位,这个值是1023,比如,2^10的E是10,保存32位浮点数时,必须保存成10+127=137,即10001001

2.2 浮点数取的过程

指数E从内存中取出可分为3种情况

1)E不全为0,或E不全为1

此时指数E的计算值减去127(或1023),得到真实值,再将有效值M前加上第一位的1

如,0.5

十进制:0.5
二进制:0.1
由于正数部分必须为1,则
将小数点右移1位:1.0*2^(-1)
其补码为:(-1)+127=126
表示为:01111110
位数去掉整数部分为0
补齐0到23位:0 01111110 00000000000000000000000

2)E全为0

此时指数E等于1-127(或1-1023)为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数,这样是为了表示\pm 0,以及接近于0的很小的数字

0 00000000 00010000000000000000000

3)E为全1

此时代表正负无穷大的数字

0 11111111 00010000000000000000000

2.3相关练习

输出结果是?

#include <stdio.h>
int main()
{
	int n = 9;
	float* p = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*p的值为:%f\n", *p);

	*p = 9.0;
	printf("n的值为:%d\n", n);
	printf("*p的值为:%f\n", *p);
	return 0;
}

答案:

n的值为:9
*p的值为:0.000000
n的值为:1091567616
*p的值为:9.000000

解析:

以整型视角存储9

00000000 00000000 00000000 00001001 //9的二进制
0 00000000 000000000000000000001001 //p认为是float类型

当内存中E全为0时,这个数字无限接近0,用%f打印小数点后6为,结果为0.000000

以float视角存储9.0

1001.0 //二进制
1.001*2^3 //化为二进制科学计数法

此时S=0,M=1.001,E=3

0 10000010 00100000000000000000000 //浮点数视角
01000001 00010000 00000000 00000000 //整型视角

将上面的二进制用%d打印出来就是一个很大的数字

本次分享就到这里,感谢阅读!

标签:存储,字节,int,浮点数,补码,基础知识,char,内存,C语言
From: https://blog.csdn.net/2402_82757055/article/details/136760349

相关文章

  • C语言解决几个常见问题
    文章目录1.数组操作2.交换数组3.求字符串的逆序排序(1)非递归的(2)递归的4.计算一个数的每位之和(递归实现)5.递归实现n的k次方1.数组操作创建一个整形数组,完成对数组的操作实现函数init()初始化数组为全0实现print()打印数组的每个元素实现reverse()函数完成数组......
  • Python《基础知识》
    1.列表:list列表内的元素通过方括号[]来表示,且可以修改例:list=[1,2,3,"fhdsj","sum"]有关list的函数:cmp(list1,list2)比较两个列表的元素len(list)返回列表元素个数max(list)返回列表元素最大值min(list)返回列表元素最小值list(seq)将元组转换为列表示例:list......
  • 输入8个整数元素存入数组中,再输入一个整数n,在数组中查找,找到了返回数组元素的下标,找不
    #include<stdio.h>intmain(){inti,n,arr[8];//Input8integerelementsintothearrayprintf("Enter8integerelements:\n");for(i=0;i<8;i++){scanf("%d",&arr[i]);}......
  • 详细解释可变参数列表C语言
    目录考研复习-函数栈帧(详解)一.什么是可变参数列表?1.1 求两个数据中的最大值1.2求多个数据中的最大值1.3逐步分析 1.va_start 2.va_arg3.va_end 4._INTSIZEOF(t)第一步理解:4的倍数第二步理解:最小4字节对齐数                第三步理解:理解源代......
  • 数据在内存中的存储
    目录1.整数在内存中的存储2.⼤⼩端字节序和字节序判断2.1什么是⼤⼩端?2.2为什么有⼤⼩端?2.3练习2.3.1练习12.3.2练习22.3.3练习33个练习小总结2.3.4练习42.3.5练习52.3.6练习63.浮点数在内存中的存储3.2浮点数的存储3.2.1浮点数存的过程3.2.2浮点数取的......
  • 【C语言】结构体
    ......
  • 实验1 C语言开发环境使用和数据类型,运算符,表达式
    #include<stdio.h>intmain(){printf("O\n");printf("<H>\n");printf("II\n");return0;}#include<stdio.h>intmain(){printf("O\n");printf("<H>\n");print......
  • C语言基础-2、字符类型
    一、字符类型char是一种整数,也是一种特殊的类型:字符。这是因为:用单引号表示的字符字面量:'a','1'''也是一个字符printf和scanf里用%c来输入输出字符1、字符的输入输出#include<stdio.h>intmain(){ charc,d; c=1; d='1'; if(c==d){ printf("相等\n"); }......
  • c语言实验一
    #include<stdio.h>#include<stdlib.h>intmain(){printf("o\to\n");printf("<H>\t<H>\n");printf("II\tII\n");system("pause");return0;}#include&......
  • ARM-V8基础知识学习笔记(一)
    参考文章:ARM官方文档ARMv8架构概述、相关技术文档以及ARMv8处理器简介ARMv8架构编程探索ARMv8架构与指令集.学习笔记 ARM异常等级:在ARMv8中,执行发生在四个异常级别之一。在AArch64中,异常级别决定了特权级别,类似于ARMv7中定义的特权级别。异常级别决定特权级别,因此在......