C语言-数据存储

🌻大小端字节序

数据存储在内存中,内存中的地址有高低地址之分,起始地址即低地址。

数据是以二进制形式存储的,二进制也有高低位之分,最左边是高位,左边是低位。

因此,数据存储时是从二进制的低位开始存储还是高位呢?

🌸取决于数据是由谁处理的——CPU架构

常见的CPU架构:X86架构->x86_64架构(向前兼容x86)。

大端字节序:低地址存高位(X86架构)。

小端字节序:低地址存低位(MIPS)。

字节序:CPU对内存中数据进行存储的顺序(不同的CPU可能会有不同的字节序)。

这就导致:不同的机器对相同数据进行解释时存在差异(二义性)。

字节序问题主要影响存储单元大于一字节数据类型的数据(short、int、long、float、double)。因为字节序主要就是以字节为单位进行存储时顺序的不同,如果一个数据只占一个字节,酒不涉及字节序的问题。

如何判断一台主机的字节序?

int a=1;//0x 00 00 00 01

对于整型变量a,如果它的起始地址是1,则主机是小端,否则是大端。

在一个整形的空间中,只取出起始地址处的一个字节数据:

char *b=(char*)&a;

完整代码:

#include<stdio.h>
#include<stdlib.h>

int main(){
    int a = 1;
    char *b = (char*)&a;
    if (*b == 1){
        printf("小端字节序\n");
    }
    else{
        printf("大端字节序\n");
    }
    system("pause");
    return 0;
}

⭐在网络通信时,当通信双方字节序不同时,使用网络字节序的标准——大端字节序

🌼基础数据类型:

整形:char、short、int、long

unsigned char、unsigned short、unsigned int、unsigned long

浮点型:float、double

🌻整形的存储

有符号数据的存储:符号位(1表示负数,0表示正数)和数值位。

无符号数据的存储:都是数值位。

例如,char类型占一个字节8个比特位,最高位是符号位,低7位是数值位。

整形的存储有三种方式:原码、反码、补码,实际存储使用补码

原码:二进制的直接解释。 -1---1000 0001 1---0000 0001

反码:对原码符号位不变,数值位取反。-1---1111 1110 1---0000 0001

补码:反码+1. -1---1111 1111 1---0000 0001

正数的原码反码补码都是一样的,与原码一致。

为什么要用补码进行存储呢?

🌸使减法可以使用加法器进行计算。

#include<stdio.h>
#include<stdlib.h>

int main(){
    //char a = 128;//0000 0000 1000 0000 截断低8位进行赋值 1000 0000
    char a = -128;//1111 1111 1000 0000  截断低8位进行赋值 1000 0000
    printf("%u\n", a);//%u表示以无符号整形进行解释——a会进行整形提升高位补1,0x FF FF FF 80
    system("pause");
    return 0;
}
运行结果:4294967168

有符号数据整形提升时,以符号位的值进行补位。

无符号数据整形提升时,以0补位(不会影响数值解释)。

#include<stdio.h>
#include<stdlib.h>

int main(){
    char a = 128;//1000 0000
    printf("%d\n", a);//%d表示十进制打印
    system("pause");
    return 0;
}
运行结果:-128

🌸128超出了char所表示的范围(-128~127),因此会给变量a一个更大的空间来存储,低位截断后仍然是1000 0000,即-128。

#include<stdio.h>
#include<stdlib.h>

int main(){
    unsigned int i;
    for (i = 9; i >= 0; i--){
        printf("%u\n", i);
    }
    system("pause");
    return 0;
}
运行结果:无限循环

🌸无符号数据不会出现负数,当i是0时,i--为-1,以无符号解释0xff ff ff ff是一个很大的数字,下次减到0的时候再进行下一次循环。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
    char a[1000];
    int i;
    for (i = 0; i < 1000; i++){
        a[i] = -1 - i;//a[i]是char类型,将-1-i的结果截取低8位进行赋值,当结果为-256时,恰好低8位是0
    }
    printf("%d", strlen(a));//strlen是求字符串的长度,其实就是看a数组哪个数据为0,数组中存储的为-1~-255,-256是结尾标志。
    system("pause");
    return 0;
}
运行结果:255

-256

10000001 00000000原码

11111110 11111111反码

11111111 00000000补码

🌻浮点型的存储

小数类型为什么叫浮点型?

🌸小数点位置是浮动的。

浮点型的存储——IEEE754标准文档规定。

例如,float占4字节,32个比特位,这32个比特位又分为三部分:

符号位:占据最高位1个比特位。0-正,1-负。

指数位:占据高位8个比特位。

尾数:占据剩余的23个比特位。

浮点型的二进制采用科学计数法(将小数点挪到第一个二进制1的后边)。

小数的二进制计算方式——乘2取整法。

例如,0.25*2=0.5->整数部分是0

0.5*2=1->整数部分是1

因此,0.25的二进制就是0.01,科学计数法就是1.0*2^-2——小数点右移了2位。

同样,5.25的二进制就是101.01,科学计数法就是1.0101*2^2——小数点左移了2位。

5.25中,符号位-S:0正数;

指数位-E:2;

尾数-M:1.0101

因为,小数点总是在第一个1的后边,因此尾数部分实际存储时会忽略前边的1,在使用时再加上(为了多节省一个比特位),即:

但是,以上存储方式存在一个问题:指数位是负数时的存储(因为指数位解释时是当做无符号解释的)。

🌸实际存储:在指数位以127作为中间基数,加上实际存储的指数数值,得到指数的实际存储。

5.25->1.0101*2^2 ->指数部分存储的就是127+2=129(1000 0001)

0.25->1.0*2^-2 ->指数部分存储的就是127+(-2)=125

因此,5.25的实际存储为:

即0x40 a8 00 00

float的数据存储范围:8个比特位的指数255(1111 1111),指数最大是128(255-127),范围为-2^128~2^128。

float尾数区域只有23个比特位,因此存储小数部分时可能会存在精度损失。

double类型:double有8个字节,64个比特位。

符号位:最高位1位。

指数位:高位11位,指数存储以中间数1023作为基数

尾数位:剩余低52位。

double类型的存储数据范围:-2^1024~+2^1024

尾数区域为52位,存储精度比float更高。

🌻浮点型的比较

浮点数不存在真正的0,只能表示一个无限接近于0的数值,且浮点数不能直接进行比较,而是以一个数值作为比较精度。

例如,

float num1,num2;
num1>num2&&num1-num2>0.0000001

指数部分全为0,表示的是一个正负0(其实是一个无限接近0的数字)。

指数部分全为1,并且尾数全为0,表示的是正负无穷大(并不表示特定值)。

#include<stdio.h>
#include<stdlib.h>

int main(){
    int a = 9;
    float *pf = (float*)&a;
    printf("%d\n", a);
    printf("%f\n", *pf);
    system("pause");
    return 0;
}
运行结果:
9
0.000000

🌸9->00000000 00000000 00000000 00001001

指数部分全为0(*2^0),因此代表的是0。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值