C语言的数据类型大全,整型数据在内存中的存储方式

       一.数据类型

         通过长时间的学习C语言以及代码的编写,我掌握了很多很多的数据类型,下面就给大家罗列一下。

        1.内置数据类型

        char        //字符数据类型——                               所占内存空间1字节

        short       //短整型——                                          所占内存空间2字节

         int         //整形——                                               所占内存空间4字节

         long        //长整型——                                     所占内存空间4/8字节——根据系统定

         long long   //更长的整形——                                所占内存空间8字节

         float       //单精度浮点数——                                所占内存空间4字节

        double      //双精度浮点数——                              所占内存空间8字节

        这些内置类型常用于变量与数组的创建与初始化,,操作系统都会根据不同的类型在内存中开辟不同大小的空间。当然,不同的操作系统,各种类型的长度都有着细微的差别,X86与X64便是32位与64位操作系统的不同。

        

        3.自定义类型(也称构造类型)

        > 数组类型      arr[ ]

        > 结构体类型  struct

        > 枚举类型     enum

        > 联合类型     union

        以上这四个类型都是元素的集合,但各有不同,我只会简单做一个区分,具体的内容会在后面的学习中专门出一期自定义类型的博客。

        结构体类型是将某个事物的共有属性集合在一起,声明一个结构体类型来描述该事物。例如学生的身高,年龄,姓名,爱好..等信息放在一起,好比一份简历一般。

        数组类型是将同一种类型的元素放在一起,当作集合展现出来。

        #define命令虽然能解决问题,但也带来了不小的副作用,导致宏名过多,代码松散,看起来总有点不舒服。C语言提供了一种枚举类型,能够列出所有可能的取值,并给它们取一个名字。比如一周的7天,多种多样的颜色等一一列举出来。 

        联合(共用体)类型:共用体的特点是各个成员共用一块内存空间。

        4.指针类型

        int *pi;                //整型指针

        char *pc;            //字符型指针      

        float* pf;             //浮点型指针

        void* pv;            //任意类型指针

        需要注意最后一种指针类型,void,在函数中我们经常可以看到函数使用void,它的作用是让函数不用返回值。但这里的void实际上代表任意类型,它不属于任何固定的类型,也可以成为任何类型(你们可以理解为泛型,不挑食的那种~)。 

        


        二.整型数据在内存中的存储方式

        1.整型数据家族

  • char(char的本质是ASCII码值,所以也归到整型家族中)

  • unsigned char
  • signed char
  • short

  • unsigned short [int]
  • signed short [int]
  • int

  • unsigned int
  • signed int
  • long

  • unsigned long [int]
  • signed long [int]

       long long

  • unsigned long long [int]
  • signed long long [int]

        这里我们需要了解一个知识点,signed 与unsigned型。一个是有符号型,一个是无符号型。有符号型表明此种类型的所有数据都会有正负数;而无符号数表明此种类型的数据是不分正负的,一律按正数处理 。而在C语言中大多编译器会将char,short,int,long型数据都定义为signed有符号型数据,所以char==signed char。通过这我们便可以得出有符号与无符号整型数据的具体范围如下。

(signed)char型数据: -2^7 ~ (2^7)-1      

-128127
 

  (signed)short型数据:-2^15 ~ (2^15)-1 

-3276832767

(signed)int型数据:-2^31 ~ (2^31)-1 

-2 147 483 6482 147 483 647

(signed)long型数据:-2^31 ~ (2^31)-1 

-2 147 483 6482 147 483 647


(unsigned)char型数据: 0~ (2^8)-1 

unsigned char0255

 (unsigned)char型数据: 0~ (2^16)-1  

unsigned short065535

(unsigned)int型数据:0 ~ (2^32)-1 

unsigned04 294 967 295

(unsigned)long型数据:0 ~ (2^32)-1 

unsigned long04 294 967 295


2. 原码、反码、补码

        计算机中的整数有三种2进制表示方法,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分,共有32位数字,最左边第一位是符号位,符号位都是用0表示“正”,用1表示“负”。

  •         数值位正数的原、反、补码都相同。
  •          负整数的三种表示方法各不相同。

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

        反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。 

        补码: 反码+1就得到补码。

        而在计算机的内存中,到底存的是哪种形式的二进制码值呢?接下来然我举个例子大家就知道了。

        代码讲解:

        通过上图代码,我们可以知道a与b值的相减是:1-1=0 ,这是十进制的减法,但计算机中并没有减法器,它只有加法器,且计算机采用的是二进制的计算,所以计算机的计算方式为:1的二进制形式+(-1)的二进制方式,那么我们可以通过计算1与-1的原码,反码,补码相加后得出计算机的计算方式。

1的原码:00000000 00000000 00000000 00000001

-1的原码: 10000000 00000000 00000000 00000001

        通过相加得:10000000 00000000 00000000 00000010——值为-2,所以可以得出计算机并非用原码作为计算方式。


1的反码:01111111 11111111 11111111 11111110

-1的反码: 11111111  11111111 11111111 11111110

        通过相加得:01111111 11111111 11111111 11111100——值很大,所以可以得出计算机也并非用反码作为计算方式。


1的补码:01111111 11111111 11111111 11111111

-1的补码: 11111111  11111111 11111111 11111111

        通过相加得:00000000 00000000 00000000 00000000,因为最高位为0,所以是正数,正数原反补码相同,所以直接输出转换十进制符合条件,值为0,所以我们可以得出计算机采用的是补码作为计算方式。

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


3.大小端字节序存储模式 

 什么大端小端?

        大端(存储)模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。

        小端(存储)模式:是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。

举个例子:int a=20;    //将20赋值给变量a  

        计算机通过赋给变量的值来确定它在内存中的存储位置!

        20转换为二进制序列为:0000 0000 0000 0000 0000 0000 0001 0100(补码)

由于二进制数字过多,采用十六进制简化(十六进制的简化:是将32bit位二进制数从右向左,每四位二进制数归为一个十六进制数。)后:0x 00 00 00 14(这便是变量a在内存中的存储地址。

        但在VS编译编译器却是以0x14 00 00 00的逆序形式展现出来,通过上面的知识点那么我们可以说明一件事:VS编译器是采用小端模式进行存储数据的。

         我们也可以采用函数来进行判断变量在内存中的存储方式,如下图:

//判断编译器使用的是什么字节序存储模式

int main() {
	int a = 1;//将1转换为二进制序列,再简化成十六进制数时为0x 00 00 00 01
	//小端存储则是0x 01 00 00 00        大端存储则是0x 00 00 00 01
	//所以可以使用强制转换为char*,让其指针只访问到十六进制的第一个字节,
	// 若第一个字节为1(01)则表明是小端
	//若第一个字节为0(00),则表明为大端。
	if (*((char*)&a) == 1) {
		printf("小端存储模式\n");
	}
	 if (*((char*)&a) == 0) {
		 printf("大端存储模式\n");
	}
	return 0;
}

        这时候大家就会想大小端字节序的存储到底有什么用?

        这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short 型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

        大多编译器比如ARM,DSP都是采用小端存储,也不排除有使用大端字节序存储的比如: KEIL C51 则 为大端模式。


        让我们来做两道道练习题.

int main() {
	int i = -20;
	unsigned  int  j = 10;
	printf("%d\n", i + j);
	//按照补码的形式进行运算,最后格式化成为有符号整数
	return 0;
}

        讲解:这是要求两数相加的十进制表现形式。通过心算可知结果为-10.那么我们就先把两个数的补码求出。

i=-20的原反补码如下:

10000000 00000000 00000000 00010100        (-20原码)

11111111   11111111   11111111   11101011        (-20反码)

11111111   11111111   11111111   11101100        (-20补码) 

j=10,为正数,其原反补码相同 

00000000 00000000 00000000 00001010      (10的补码)

i+j 

11111111   11111111   11111111   11101100        (-20补码)                 +

00000000 00000000 00000000 00001010      (10的补码)


(11111111   11111111   11111111   11110110)i+j补码

         求%d有符号十进制数,因为无符号型数+有符号型数=无符号型数字,无符号型数字展现出有符号型的十进制数字,需要看二进制序列的最高位,为1(负数),所以需要转换为原码输出。

(11111111    11111111  11111111   11110110)——> 

(11111111    11111111  11111111   11110101)

(10000000   00000000 00000000  00001010)i+j的原码——>转换为十进制数为-10.

最后来一道题:

#include<stdio.h>
#include<string.h>
int main()
{
    if(strlen("abc")-strlen("abcdef")>0){

    printf("是正数\n");
        }
    else{
    printf("是负数");
    }
    return 0;
}

        这道题设计到无符号整数的知识点。先来看strlen("abc")它的大小为3(strlen遇到字符串的'\0'会自动停止计算),strlen("abcdef")它的大小为6,一般情况下3-6=-3<0,应当输出“ 是负数 ”。

        但结果却相反,输出的“ 是负数 ”。原因在于strlen的返回值是size_t类型值,size_t是无符号型整数(unsigned),所以3-6=-3,-3在无符号型数中是一个很大的正值 。一个无符号型整数值减去一个无符号型整数值,得出的结果仍然是一个无符号型整数值,而无符号型整数值永远都是大于等于0的,所以结果输出“是正数”。

-3转换为二进制序列时:10000000 00000000 00000000 00000011(原码)

                                       11111111 11111111 11111111 11111100(反码)

                                       11111111 11111111 11111111 11111101(补码)

系统认为这个二进制补码值是无符号型,无符号型不分正负(永为正),所以原反补相同,直接转换成十进制输出,通过计算器转换十进制,结果为42亿多。

                                

        好了,以上就是整数数据在内存中的讲解了,觉得有用的话点个关注吧!!谢谢了!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙予清的zzz~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值