首页 > 其他分享 >C语言-数据存储详解

C语言-数据存储详解

时间:2023-06-17 18:01:33浏览次数:50  
标签:11111111 存储 00000000 C语言 int 详解 printf pFloat

 C语言类型


内置类型


整型家族

char //字符数据类型 1个字节

unsigned char

signed char

short//短整型 4个字节

unsigned short [int]

signed short [int]

int //整型 4个字节

 unsigned int 

 signed int 

long//长整型 8个字节

unsigned long [int]

 signed long [int]

long long //更长整型 8个字节


浮点家族


float//单精度浮点数 4个字节

double//双精度浮点数8个字节




自定义类型(构造类型)

数组类型 arr[10]

结构体类型 struct

枚举类型 enum

联合类型 union


指针类型

int *i

char *c

float *fl

void * vo

空类型

void 通常用于函数的返回类型,void 指的是无返回值


类型的意义

1.使用这个类型开辟内存空间的大小

2.如何看待内存空间的视角。

比如我们使用int 我们认为开辟的这个空间就是来存整数的。如果使用float我们就认为这个空间是用来存储浮点数。


整型在内存中的存储

计算机中的有符号整数有三种表示方法,原码反码补码

(无符号数 原码补码反码均相同,存储方式只有一种可以理解按照原码即为其二进制类型存储。)

三种表示方法均有符号位和数值位两部分组成,符号为是第一位,0代表正1代表负数 。数值位的表示方法则各不相同。

原码

直接将二进制按照正负数的形式存储

反码

符号为不变,其他位相较于原码依次取反

补码

在反码的基础上+1

举个例子

int a=10;
//00000000 00000000 00000000 00001010 原码
//00000000 00000000 00000000 00001010 补码
//00000000 00000000 00000000 00001010 反码
    printf("%x\n",a);//十六进制 00 00 00 0a
int b=-10;
//10000000 00000000 00000000 00001010 原码
//11111111 11111111 11111111 11110101 补码
//11111111 11111111 11111111 11110110 补码
    printf("%x\n",b);//ff ff ff f6

这个例子说明了整型在内存中存储是按照补码存储的。

原因是:使用补码,可以讲符号位和数值位统一处理,同时加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。


计算机中减法其实并不是直接减而是加上一个被减数的负数

例如 1+1 

在计算机中运算是1+(-1)来运算的,如果使用原码 大家可以自己算一下,是算不出来0这个结果的,但是使用补码就可以。

另外 实际内存中存储的时候分为大端存储和小端存储。

我们知道地址有低位和高位从左到右,那么整型所占据的32位第0位就是低位,第31位就是高位。


大端存储

数据字段的高位存储在地址的低位

例如 我们上述代码中的00 00 00 0a 

第一个00是这个数据的高位 它存放在地址靠左也就是地址的低位我们称之为大端存储。


小端存储 

数据字段的低位存储在地址的低位

例如 我们上述代码中的00 00 00 0a 

在存储中存储的方式是 0a 00 00 00

第一个00是这个数据的高位 它存放在地址靠右也就是地址的高位我们称之为大端存储 

我们可以写一段很简单的代码来判断自己的机器是大端还是小端存储

int main(){
    int a=1;
    char *p=(char *)&a;
    if(*p==1){
        printf("小端存储");

    }else{
        printf("大端存储");
    }

return 0;
}


关于这个地方有个比较有意思的题:

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

猜想一下输出的答案是什么

答案是:4294967168

char a =-128;
10000000 00000000 00000000 10000000 原
11111111 11111111 11111111 01111111 反
11111111 11111111 11111111 10000000 补
因为是char类型 截出来最后八位
10000000
输出是%u无符号十进制
整型提升
本身是个负数提升的时候高位补充1
11111111 11111111 11111111 10000000 补
正常情况 十进制输出时要算出来它的反码和原码 但是这里是%u 这个补码就是原码 
不需要再反向求出其反码和原码了 转换成十进制输出就可以了

C语言-数据存储详解_数据存储

浮点数在内存中的存储

先给出来一个例子

void float_EX1(){
    
    /* 输出结果为:
     * n的值位:9
     * *pFloat的值位:0.000000
     * n的值为:1091567616
     * *pFloat的值为:9.000000
     */
    int n=9;
    float *pFloat= (float *)&n;
    printf("n的值位:%d\n",n);
    printf("*pFloat的值位:%f\n",*pFloat);

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

从这个例子我们首先可以得出结论:

整型存 只能用整型存储 不能用浮点型来取出来,浮点型存也只能用浮点型存储 不能用整型存

也就是说,整型在内存中存储与浮点型在内存中存储的方式是不同的。

 根据IEEE 754 标准中定义

C语言-数据存储详解_整型_02

有符号零和非零的浮点型数都可以用

C语言-数据存储详解_补码_03

这个式子来表示。例如5.0 是 101.0  即(-1)^0 * 2^2* 1.01  对应 s=0,b为2 e为2 m为1.01 。

32位的单精度浮点数二十进制浮点数表示方式定义如下:

C语言-数据存储详解_浮点型_04

图1

C语言-数据存储详解_补码_05

图2

根据这个表可以得知

在32位下

1个bit位的符号位S

8个bit位的指数E

还有23个bit位的有效数字t

在64位下

1个bit位的符号位S

11个bit位的指数E

52个bit位的有效数字t

其他16或128请读者自行参考。


但是实际存储时,我们会发现所有的浮点型都能转换成1.****也就是说这个小数点前面的1是固定的。所以又可以省略一位只保留小数点后面这样有效为数字M就有多了一位,其精度就更高了

E的特殊情况

除此之外还有个关键的问题:

假设要存储0.5应该怎么存?

是这样:

0.5

转换成754种定义的是:

0.1 注意里0.1并不是十进制的0.1(小数点后面的值要用2的负数次幂表示 因为0.5是2^(-1) ,0.25就是2^(-2))

而是 

2的-1次幂 2^(-1)就是0.5

转换成标准定义

(-1)^0 * 1.0 * 2^(-1)

所以实际情况中这个E有可能是负的

但是E中8个bit位并没有符号位那这里怎么办?

754中是这样的:让E=e(真实的幂值)+ bias(偏移量)

比如8个bit位我们让bias等于127 11个bit位的让bias等于1023

这样不管是多少最后都是一个正值

比如上面那个0.5的例子

S=0;

M=1.0;

e=-1

但真正的E=e+127=126 

所以在真正存储的时候存的是126

那我们再写个例子验证一下

void float_EX2(){
    float  f =3.5;
    int  *pf=(int *)&f;
    //3.5
    //11.1
    //(-1)^0 * 1.11 *2 ^ 1
    //S=0
    //M=1.11
    //E=128  10000000
    //0 10000000 11000000000000000000000 二进制
    //0100 0000 0110 0000 0000 0000 0000 0000
    //40600000 十六进制
    printf("3.5在内存中存储的16进制是");
    printf("%x\n",*pf);
    //结果为 40b00000
    //与计算结果一致
}

C语言-数据存储详解_浮点型_06


当然754中还规定了如果发现E为全0和E为全1的情况:

E为全零

E为全0代表的就是 2^(-127) 这样一个数字我们可以想一下2的32次方已经是个很大的数字了那么2的127次幂将会有多大,那如果将2的127次幂放入分母,这个数我们就认为它无限接近为零其实就是+- 无穷小了。


E为全1

与上面类似,E为全一 代表的是 2^128 即表示这个数字无穷大


最后我们再回顾上面给出的例子float_EX1()

void float_EX1(){
    
    /* 输出结果为:
     * n的值位:9
     * *pFloat的值位:0.000000
     * n的值为:1091567616
     * *pFloat的值为:9.000000
     */
    int n=9;
    float *pFloat= (float *)&n;
    printf("n的值位:%d\n",n);
    printf("*pFloat的值位:%f\n",*pFloat);

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

整数 9

在内存中存储的补码是00000000 00000000 00000000 00001001

那么以浮点型指针访问并且以浮点型输出

就认为

符号为0  指数E00000000 有效位0000000 00000000 00001001

用754种定义的 标准格式

(-1)^0 * 0000000 00000000 00001001 * 2 ^(-126)

%f 只打印小数点后六位 所以输出的时候 是0.000000


然后再来分析

 *pFloat=9.0;

这个时候需要以浮点型去存

1001.0

1.001 *2^3

(-1)^0 * 1.001 ^ 2^3

S=0

M=001

E=3+127=130

0 10000010 00100000000000000000000

C语言-数据存储详解_补码_07

我们对照其二进制

发现 0 10000010 00100000000000000000000 的值转化为10进制

就是1091567616


最后一个输出9.0 是因为我们以浮点数存以浮点数取出当然就还是9.0了


至此 数据存储就结束了,有问题欢迎讨论。


 

标签:11111111,存储,00000000,C语言,int,详解,printf,pFloat
From: https://blog.51cto.com/u_16160587/6505731

相关文章

  • RoundingMode 几个参数详解
    第一版java.math.RoundingMode几个参数详解java.math.RoundingMode里面有几个参数搞得我有点晕,现以个人理解对其一一进行总结:为了能更好理解,我们可以画一个XY轴RoundingMode.CEILING:取右边最近的整数RoundingMode.DOWN:去掉小数部分取整,也就是正数取左边,负数取右边,相当于向原点靠近......
  • C语言基础教学(文件操作)
    (文章目录)前言这篇文章我们来讲解C语言中的文件操作,文件操作在C语言中算是一个比较重要的知识点,我们每天都在和文件打交道,各种文件夹的打开和关闭操作,那么这篇文件带大家学习如何使用C语言中的文件操作来完成这个工作。一、文件操作基本介绍C语言提供了一组函数,可以用于进行......
  • 随心所欲玩复制 详解robocopy (完)
    摘自:https://www.ngui.cc/el/955886.html?action=onClick通过本系列前面四篇文章的介绍,大体上对robocopy有了全面的讲解,针对常用的操作也做了比较充分的说明。其实在WindowsServer中,大部分的备份工作都是通过这个命令来实现的。在这最后一篇文章中,给出robocopy的命令格式以及所......
  • MultipartFile工具类(方法详解)
    最近项目一直在接触和文件上传相关的知识,趁最近忙里偷闲,那就从基础开始一点点的整理相关知识吧!首先我们要认识一下Java中的流1、“流”是一个抽象的概念,它是对输入输出设备的一种抽象理解,在java中,对数据的输入输出操作都是以“流”的方式进行的。2、“流”具有方向性,输入流、输......
  • VMIC5565反射内存卡供应厂家 PCI-5565多模光钎网络 GE反射内存模块 VMIC反射内存PMC系
    反射内存实时网的特点VMIC反射内存是一种通过局域网在互连的计算机间提供的数据传输的技术,强实时网络设计人员已经越来越多地采用这种技术。VMIC反射内存实时局域网的概念十分简单,就是设计一种网络内存板,在分布系统中实现内存至内存的通信,并且没有软件开销。每台结点机上插一块反射......
  • CMU15445 (Fall 2020) 数据库系统 Project#3 - Query Execution 详解
    前言经过前两个实验的铺垫,终于到了执行SQL语句的时候了。这篇博客将会介绍SQL执行计划实验的实现过程,下面进入正题。总体架构一条SQL查询的处理流程如下为:SQL被Parser解析为抽象语法树ASTBinber将AST转换为Bustub可以理解的更高级的ASTTreerewriter将语法......
  • 一文详解图卷积神经网络
    本文是文章AGentleIntroductiontoGraphNeuralNetworks的个人笔记,强烈建议大家去体验原文的交互式阅读,以及李沐老师的讲解。我的宗旨是尽量使用浅显易懂的白话,而不是晦涩的术语,把概念和理论讲清楚。开始吧!作为一枚资(ruo)深(ji)NLPer,我常见的神经网络输入是一段文本序......
  • Vue进阶(幺贰柒):插槽详解
    (文章目录)一、概述插槽就是子组件中用slot标签定义的预留位置,可以设置name属性,也可以不设置name属性,设置name属性的叫具名插槽,不设置name属性的叫不具名插槽,在父组件中使用子组件时候,可以在使用子组件标签内通过声明插槽名或不声明插槽名的方式往子组件中的具名插槽或者不具名插......
  • C语言中的转义字符及注意事项
    在C语言中,转义字符是由一个反斜杠(\)和一个特定字符组成的组合。它们用于表示一些特殊的控制字符,例如在字符串中插入换行符或者制表符。当编译器遇到一个反斜杠时,它会将其后面的字符解释为一个转义字符,简单来说,转义字符就是反斜杠加上某个特定的字符,改变其原本含义,来表示另一个含义......
  • c语言练习
    3.C语言预备知识3.1字符常量题目:熟悉C语言程序的字符常量输出的基本编写源代码:#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>intmain(){ inta1=20,a2=345,a3=700,a4=22; intb1=56720,b2=9999,b3=20098,b4=2; intc1=233,c2=205,c......