【C语言-----数据存储:整型存储】

深度剖析数据在内存中的存储

类型的意义:

1.使用这个类型开辟的内存空间的大小(大小决定了使用范围)
2.如何看待内存空间的视角

类型的基本归类:

整型家族:

char //字符的本质是ASCII码值,是整形,所以划分到整形家族

unsigned char

signed char //char a; char到底是unsigned char还是signed char,取决于编译器,标准未定义

short

unsigned short [int]

signed short [int]

int

unsigned int

signed int --> int

long

unsigned long [int]

signed long [int]

long long

unsigned long long [int]

signed long long [int]

注意:除了char类型的定义是由编译器决定是否默认有符号位的,其他整型类型的数据,默认为signed类型

在日常生活中,有些数据是没有负数的,比如:身高、体重、年龄,这种情况就要使用unsigned 类型的数据。

而在unsigned类型数据中,二进制的最高位变成了有效数据位。

而在signed类型数据中,二进制的最高位变成了符号位。

浮点型家族(只要是表示小数就可以使用浮点型数据):

float //精度较低,存储的范围较小

double //精度较高,存储的范围较大

构造类型(自定义类型):

我们可以自己创建出新的类型:

数组类型

结构体类型 struct

枚举类型 enum

联合类型 union

指针类型:

int* p;

float* p;

char* p;

void* p;

空类型:

void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型

整型在内存中的存储:

一个变量的创建是要在内存中开辟空间。空间的大小是根据不同的类型而决定的。

比如:

//数值的表示形式:
//2进制
//8进制
//10进制
//16进制

//整数的2进制表示也有三种表示形式:
//正数的原、反、补码相同
//负数的原、反、补码需要进行计算得出
//1.原码:直接通过正负的形式写出的二进制序列就是原码
//2.反码:原码的符号位不变,其他位按位取反得到的就是反码
//3.补码:反码+1就是补码

//为了方便表示,通常把4个二进制位变成一个16进制位,但是内存中还是以二进制补码的形式储存的
int a=10;	//正数在内存中如何存储,一个整型占4个字节
//a因为是正数,所以原反补码都相同
//bit:00000000000000000000000000001010	-原
//hex:0x00 00 00 0a 	//内存展示给我们的数据
//bit:00000000000000000000000000001010	-反
//hex:0x00 00 00 0a
//bit:00000000000000000000000000001010	-补
//hex:0x00 00 00 0a

int b=-10;	//负数在内存中如何存储
//bit:10000000000000000000000000001010	-原	
//hex:0x80 00 00 0a
//bit:11111111111111111111111111110101	-反		符号位不变
//hex:0xff ff ff fa
//bit:11111111111111111111111111110110	-补		反码+1
//hex:0xff ff ff f6

//补码的补码等于原码
//-10的原码:10000000000000000000000000001010
//-10的反码:11111111111111111111111111110101
//-10的补码:11111111111111111111111111110110

//-10的补码的原码:11111111111111111111111111110110
//-10的补码的反码:10000000000000000000000000001001
//-10的补码的补码:10000000000000000000000000001010

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

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理。

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

我们可以看到在内存中对于a和b分别存储的是补码,但是我们发现顺序有点不对劲。

大小端介绍

大小端:只是数据在内存中存储的方式,取决于硬件电路。

大端【字节序】存储:

把一个高位字节序的内容存放到低地址处,把低位字节序的内容存放到高地址处,这就是大端字节序存储。

小端【字节序】存储:

把一个低位字节序的内容存放到低地址处,把高位字节序的内容存放到高地址处,这就是小端字节序存储。

口诀:左低右高,正序大端,逆序小端

****百度系统工程师面试题,要求你写一个简单的程序,判断数据是大端存储还是小端储存****

整型存储练习1:

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;
}

-1的原码:100000000000000000000000000000001

反码:111111111111111111111111111111110 (原码除了符号位其他位取反)

补码:111111111111111111111111111111111 (反码+1等于补码)

但是由于a是字符型的数据,只有一个字节(8个bit位),但是-1的补码有32个bit位。

所以需要把补码的数据:111111111111111111111111111111111,截断成:11111111,存放进a里,这种操纵称为截断数据。

截断位时,截断的是数值对应的二进制序列的低位,跟大小无关

整形提升的时候有符号位看高位是0/1进行补位,无符号位高位补0。

先用unsigned/signed决定整型提升补位的是0还是1,再用数据表示类型符%d决定是否有符号用于决定补码转原码的流程。

整型存储练习2:

int main()
{
	unsigned int i;
    for(i=9;i>=0;i--)
    {
        printf("%u\n",i);		
    }
    return 0;
}

问:思考这个程序的效果是怎么样的?

结果:死循环。

解析:i为一个unsigned int类型,for循环里循环条件为i小于等于0,通常我们会以为这个程序只会打印9--1的数字。但是,由于我们的i是一个unsigned int类型的,是一个无符号数,当程序执行到-1时,-1存到i中,i就把-1看成一个很大的数。

-1的原码:10000000000000000000000000000001

-1的反码:11111111111111111111111111111110

-1的补码:11111111111111111111111111111111 (最高位为符号位)

因为我们的i是无符号(unsigned int)类型的数据,当-1存到i的时候,i会把最高位当成有效位。

所以-1存到i的时候,是一个非常大的整数。

整型存储练习3:

int main()
{
	char a[1000];
    int i;
    for(i=0;i<1000;i++)
    {
        a[i]=-1-i;
    }
    printf("%d",strlen(a));
    return 0;
}

问:a执行完的长度是多少?

结果:255。

char 类型的取值范围:~127-128。

当程序执行到-128的时候,在进行-1-128的操作由于char的取值范围是~128-127,当i变成-129的时候,i会变成127

-129的原码:10000000000000000000000010000001

-129的反码:11111111111111111111111101111110

-129的补码:11111111111111111111111101111111

但是a是char类型的数据,只能存放一个字节,8个bit位,所以要进行截断:01111111。

截断的数据等于a里面存储的数据:01111111。

但需要进行操作时,根据是否是unsigned / signed 的类型进行提升。

如果是unsigned ,就不需要根据最高位的符号位进行提升。

如果是signed,就需要根据最高位的符号位进行提升。

char在visual studio 2022编译器中默认是signed 类型的,所以需要根据符号位进行整型提升。

提升后的值:00000000000000000000000001111111

根据符号位,判断它是一个正数,正数原反补码相同,所以提升后的值等于127。像一个圆环一样循环下去。

整型数据存储练习4:

unsigned char i=0;
int main()
{
	for(i=0;i<=255;i++)
    {
        printf("hello world!\n");     
    }
    return 0;
}

问:会打印多少个hello world!

结果:死循环。

unsigned char 类型取值范围:0~255。

但是程序for循环到256,超越了i的取值范围,它会变成0,重新执行循环。

整型数据存储练习5:

int main()
{
    if(strlen("abc")-strlen("abcdef")>=0)
        printf("<\n);
    else
        printf(">\n);
	return 0;
}

问:打印>还是<?

结果:<.

strlen函数一个unsigend 类型的数据,返回的是无符号的数据,两个无符号的数据相减

正常的计算3-6的值等于-3

但是strlen是无符号的,两个无符号数进行操作得到的也是一个无符号的数

-3就转换成一个非常大的正数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值