数据的存储讲解附带例题详解

整数在内存中的存储

变量的创建需要在内存中开辟空间,空间的大小根据类型决定

计算机中的符号数有三种表示方法:原码、反码及补码
三种表示方法均有符号位和数值位两部分组成,符号位0表示正,1表示负
原码: 直接将数值按着正负数的形式翻译成二进制
反码: 将原码的符号位不变,其他位按位取反
补码: 反码+1
其中正数的原码反码补码均相同
对于整形来说,数据存放在内存中存放的是补码
原因:使用补码时,可以将符号位与数值位一同进行处理,加法和减法也可以一同处理(CPU中只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

在计算机中存储数字的时候,是分为大小端进行存储的
那么什么是大小端?

大端存储模式

数据的低位存储在内存的高地址处,而数据的高位存放在内存的低地址处

小端存储模式

数据的低位存储在内存的低地址处,而数据的高位保存在内存的高地址处

为什么会有大小端?
在计算机系统中,以字节为单位,那么每个地址单元都对应着一个字节(8bit)但是在C语言中除了用8bit的char类型之外,还有16bit的short类型,32bit的long型(取决于编译器)另外对于位数大于8位的处理器(如16、32位的处理器)由于寄存器的宽度大于一个字节,那么必然存在将多字节安排的问题,由此就导致了有大端和小端存储模式
比如0x1122,那么0x11为高字节,0x22为低字节;那么对于大端存储,就将低字节的内容存放在内存的高地址处,0x11存放在低地址处

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

int main()
{
    int a = 1;// a在内存中16进制表示形式:0x 00 00 00 01 字节序 01为低字节内容
    char* p = (char *)&a;//取出第一个字节的地址内容(低地址) 查看是否为1
    if (*p == 1)
    {
        printf("小端");
    }
    else
    {
        printf("大端");
    }
    return 0;
}

隐式类型转换

C的整形算术运算总是以缺省整形的精度来进行的。为了获取这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这个过程被称为整形提升。

整形提升的意义: 表达式的整形运算要在CPU的相应运算器件中执行,CPU内运算器ALU的操作数长度一般就是int大小的字节长度,同时也是CPU通用寄存器的长度。因此,即使是两个char类型的相加,在CPU中执行时也是要先转换为CPU内整形操作数的标准长度。通用CPU是难以实现两个8比特字节直接相加运算,所以表达式中各种长度小于int长度的整形值,都必须先转换为int或者unsigned int类型,然后才能被送入CPU去执行运算。
整形提升:
如果是有符号类型,按着符号位进行整形提升,即高位补符号位
如果是无符号类型,高位补0

接下来来看几道例题

int main()
{
    char a = 3;
    //00000011
    //首先字符型要转换为整形进行运算(整形提升),a是有符号数,所以高位补0
    //00000000000000000000000000000011原码=补码
    char b = 127;//2^7-1
    //01111111 高位补0
    //00000000000000000000000001111111原码=补码
    //c = a + b
    //00000000000000000000000010000010 此时运算结束,由于c是8bit的,所以发生整形截断
    //10000010 此时为c在内存中的补码 之后转换为原码
    //11111111111111111111111110000010 补码
    //11111111111111111111111110000001 反码 = 补码 - 1
    //10000000000000000000000001111110 原码 = -126
    char c = a + b;
    printf("%d\n", c);//-126
    return 0;
}
int main()
{
    char a = -1;//默认为有符号类型
    //10000000000000000000000000000001 -1的原码
    //11111111111111111111111111111110  反码
    //11111111111111111111111111111111  补码
    //发生截断
    //11111111  %d按着有符号位进行打印
    //发生整形提升 a是有符号的 又由于符号位为1 所以补1
    //11111111111111111111111111111111  补码--算出原码进行打印
    //11111111111111111111111111111110  反码
    //10000000000000000000000000000001  原码  -1
    signed char b = -1;//b与a一样都是有符号
    unsigned char c = -1;
    //整形提升 高位补0
    //c对11111111(和上面计算相同)进行整形提升
    //00000000000000000000000011111111  整数:补码=反码=原码
    printf("a=%d b=%d c=%d", a, b, c);//-1 -1 255
    return 0;
}
int main()
{
    //整形提升 如果是有符号数 按着符号位进行提升 如果是无符号数就补0
    char a = -128;
    //10000000000000000000000010000000 -128的原码
    //11111111111111111111111101111111 反码
    //11111111111111111111111110000000 补码--内存中的数字
    //由于char是一个字节 只有8bit 所以发生整形截断
    //10000000  补码 整形提升提升符号位 发生整形提升 因为a是有符号的数
    //11111111111111111111111110000000 补码这个数打印就是超大的数--无符号数 直接就是原码
    printf("%u\n", a);//%u以无符号数打印整形 认为内存中存的是无符号数 原码反码补码是一个值
    return 0;
}
int main()
{
    //整形提升 如果是有符号数 按着符号位进行提升 如果是无符号数就补0
    char a = -128;
    //10000000000000000000000010000000 -128的原码
    //11111111111111111111111101111111 反码
    //11111111111111111111111110000000 补码--内存中的数字
    //由于char是一个字节 只有8bit 所以发生整形截断
    //10000000  补码 整形提升提升符号位 发生整形提升 因为a是有符号的数
    //11111111111111111111111110000000 补码这个数打印就是超大的数--无符号数 直接就是原码
    printf("%u\n", a);//%u以无符号数打印整形 认为内存中存的是无符号数 原码反码补码是一个值 所以结果为一个超大的数
    return 0;
}
int main()
{
    char a = 128;//-128~127意思是char容纳的值
    //00000000000000000000000010000000  原码=反码=补码
    //截断
    //10000000 发生提升 a是有符号数 按着符号位进行提升
    //11111111111111111111111110000000
    printf("%u\n", a);//超大的数
    return 0;
}
int main()
{
    int i = -20;
    //10000000000000000000000000010100  原码
    //11111111111111111111111111101011  反码
    //11111111111111111111111111101100  补码
    unsigned int j = 10;
    //00000000000000000000000000001010  原码=反码=补码
    //补码相加
    //11111111111111111111111111110110  i+j结果的补码
    //11111111111111111111111111110101  反码
    //10000000000000000000000000001010  原码-10
    printf("%d\n", i + j);//-10
    return 0;
}
int main()
{
    unsigned int i;//无符号i不可能小于0
    //死循环
    //-1在内存中的补码:11111111111111111111111111111111--无符号数 所有位都是有效位就是超大的正数
    for (i = 9; i >= 0; i--)//i >= 0 恒成立死循环
    {
        printf("%u\n", i);
    }
    return 0;
}
int main()
{
    char a[1000];
    int i;
    for (i = 0; i < 1000; i++)
    {
        a[i] = -1 - i;
    }
    //数组中的数 -1 -2 -3 ... -128 127 126 ... 3 2 1 \0 总共256个 长度为255 因为不算\0
    printf("%d", strlen(a));//255
    return 0;
}
#include <stdio.h>
unsigned char i = 0;//无符号char范围:0~255
int main()
{
    for (i = 0; i <= 255; i++)//255+1=0
    {
        printf("hello world\n");
    }//死循环
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值