IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C进阶——数据的存储(整形) -> 正文阅读

[C++知识库]C进阶——数据的存储(整形)

C语言的基础知识我们已经经过了简单的了解,现在我们开启C语言中进阶的部分。

????????在之前的文章中我们简单的提及过Debug和Release两种编译方式在编译时的区别。

现在我们在使用上次的一个例子来进行说明:

#include <stdio.h>

int main(void)
{
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for ( i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}
	return 0;
}

????????这段代码在VS2017编译器下在Debug版本下执行的结果是死循环,而在Release版本下执行的结果是有限值,这种现象我们同样可以通过打印地址的方式来发现其中的原因。

	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	
	printf("%p\n", &i);     
	printf("%p\n", &arr[0]);
    
    //在Debug版本下运行的结果
    //00EFF760
    //00EFF730

    //在Release版本下运行的结果
    //0056F730
    //0056F734

从上面的运行结果结果中我们就可以发现:在Debug版本下数组的首地址比变量i的地址小,而在Release版本下数组的首地址比变量的地址大。这就说明了Release版本会对我们的代码进行优化

数据在内存中的存储

数据类型的详细介绍

基本的内置类型:

char? (1)? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//字符数据类型

short? (2)? ? ? ? ? ? ? ? ? ? ? ? ? ? //短整型

int? (4)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //整型

long? (4/8)? ? ? ? ? ? ? ? ? ? ? ? ? //长整型

long long? (8)? ? ? ? ? ? ? ? ? ? ?//更长的整型

float? (4)? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//单精度浮点型

double? (8)? ? ? ? ? ? ? ? ? ? ? ? ?//双精度浮点型

类型的意义:

? ? ? ? 1.使用该类型开辟的内存空间的大小(大小决定了使用范围)。

? ? ? ? 2.看待内存的视角。同样的数据,如果使用的是浮点类型,内存就会将它视为浮点类型的数据;如果是整型,内存就会将它视为一个整型数据。

数据的基本归类

整型家族

char
????????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]

注:

? ? ? ? 1.字符的本质是ASCII码,是整型划分到整型家族;char是unsigned char还是signed char的标准未定义,取决于编译器的实现

? ? ? ? 2.int a;——>signed int a;

浮点型家族

float

double

只要是表示小数就可以使用浮点类型,float的精度低,存储的数值范围较小,double类型的精度高,存储的数据的范围更大。

构造类型????????自定义类型 - 我们可以自己创建出新的类型

数组类型 int[ ]
结构体类型 struct
枚举类型 enum
联合类型 union

指针类型

int *pi;
char *pc;
float* pf;
void* pv;

空类型

void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型

//第一个void 表示函数不会返回值
//第二个void 表示函数不需要传入任何参数
void test(void)
{
	printf("hhh");
}
int main(void)
{
	test();
	return 0;
}

整型在内存中的存储

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

例如:int a = 20;????????int b = -10;????????a就是占据了四个字节的空间。

原码、反码、补码

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

这三种表示方法都有符号位与数值位,符号位使用0表示正,使用1代表负。

对于正数而言,原码、反码、补码都相同。

对于负数:

原码:直接将二进制按照正负数的形式翻译成二进制

反码:源码的符号位不变,其它位依次取反

补码:反码的二进制数 + 1

	int a = 20;
	//00000000 00000000 00000000 00010100
	//00000000 00000000 00000000 00010100
	//00000000 00000000 00000000 00010100 	//0x 00 00 00 14

	int b = -10;
	//10000000 00000000 00000000 00001010 - 原码
	//11111111 11111111 11111111 11110101 - 反码
	//11111111 11111111 11111111 11110110 - 补码 	//0x ff ff ff f6

?

?????????通过代码的实现我们可以得到在计算机的内存中存放的补码。

对于整型来说,数据在内存中存放的是补码。

原因:

????????在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

在计算机中计算1-1时,是看做1+(-1)的运算
00000000 00000000 00000000 00000001

10000000 00000000 00000000 00000001 - 原码
11111111 11111111 11111111 11111110 - 反码
11111111 11111111 11111111 11111111 - 补码

结果为:
1 00000000 00000000 00000000 00000000 
由于只有32位,高位丢失,因此结果为:
00000000 00000000 00000000 00000000 

补码 = 原码取反 + 1??;原码? = 补码取反 +1? ? ? ? ?补码和原码可以互相转化

在分析调试结果后,得到了在内存中存储的是补码,但是同样可以看到补码以16进制存储的顺序感觉怪怪的,下面来介绍一下其中的原因。

大小端字节序的介绍及判断

什么是大小端:

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

为什么会有大小端:

为什么会有大小端模式之分呢?

????????这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就
导致了大端存储模式和小端存储模式。
????????例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中,0x22 放在高地址中,即 0x0011 中。小端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

分享一道有关的题目:请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

//这是我自己编写的简单的方法,通过判断内存中地址前进的步长来判断是哪一种存储模式
int main(void)
{
	int a = 1;
	char* p = &a;
	printf("%p\n", p);
	printf("%p\n", p + 1);
	printf("%d\n", *p);
	printf("%d\n", *(p + 1));
	return 0;
}

//这个是优化完的代码
#include <stdio.h>
int check_sys()
{
	int i = 1;
	return (*(char *)&i);
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

?一些跟数据存储相关的练习题

1.
    #include <stdio.h>
    int main()
    {
        char a= -1;
        //10000000 00000000 00000000 00000001 - 原码
        //11111111 11111111 11111111 11111110 - 反码
        //11111111 11111111 11111111 11111111 - 补码
        //11111111 截断 - a
        
        //printf("a=%d",a);
        //有符号数
        //11111111 11111111 11111111 11111111 整形提升 - 补码
        //10000000 00000000 00000000 00000000 - 反码
        //10000000 00000000 00000000 00000001 - 原码
        //-1
        
        signed char b=-1;
        //10000000 00000000 00000000 00000001 - 原码
        //11111111 11111111 11111111 11111110 - 反码
        //11111111 11111111 11111111 11111111 - 补码
        //11111111 截断 - b
       
        //printf("b=%d",b);
        //有符号数
        //11111111 11111111 11111111 11111111 整形提升 - 补码
        //10000000 00000000 00000000 00000000 - 反码
        //10000000 00000000 00000000 00000001 - 原码
        //-1
        
        unsigned char c=-1;
        //10000000 00000000 00000000 00000001 - 原码
        //11111111 11111111 11111111 11111110 - 反码
        //11111111 11111111 11111111 11111111 - 补码
        //11111111 截断 - c
        //无符号数
        //00000000 00000000 00000000 11111111 整形提升 - 补码

        // %d 打印有符号的整形 打印的是原码
        printf("a=%d,b=%d,c=%d",a,b,c);//a = -1;b = -1;c = 255
        return 0;
    }
2.
    #include <stdio.h>
    int main()
    {
        char a = -128;
        //一个有符号的char类型的范围时-128~127
        //1000000 00000000 00000000 10000000 - 原码
        //1111111 11111111 11111111 01111111 - 反码
        //1111111 11111111 11111111 10000000 - 补码
        //1000000 - 截断
        //1111111 11111111 11111111 10000000 - 整形提升 - 补码
        printf("%u\n",a);//打印的结果为无符号数 - 4294967168
        return 0;
    }

3.
//结果与2一致
    #include <stdio.h>
    int main()
    {
        char a = 128;
        printf("%u\n",a);
        return 0;
    }
4.
    int i= -20;
    //10000000 00000000 00000000 00010100 - 原码
    //11111111 11111111 11111111 11101011
    //11111111 11111111 11111111 11101100 - 补码

    unsigned int j = 10;
    //00000000 00000000 00000000 00001010
    
    //11111111 11111111 11111111 11101100
    //00000000 00000000 00000000 00001010
    //11111111 11111111 11111111 11110110 i + j - 补码

    //11111111 11111111 11111111 11110110 i + j - 补码
    //10000000 00000000 00000000 00001001 
    //10000000 00000000 00000000 00001010 - 输出结果 - 原码
    printf("%d\n", i+j);
5.
    int main(void)
    {
    	unsigned int i;
	    for (i = 9; i >= 0; i--)
	    {
	    	printf("%u\n", i);
    	}

    	return 0;
    }
//程序当i的值到0之前的数值都是正常打印9 8 7 6 5 4 3 2 1 0
//当达到0时,进行下一步操作 0-1 ,我们将其看做 0 + (-1)
//结果为:
//00000000 00000000 00000000 00000000 - 0

//10000000 00000000 00000000 00000001 - -1 - 原码
//11111111 11111111 11111111 11111110
//11111111 11111111 11111111 11111111 - 补码

//00000000 00000000 00000000 00000000 - 0
//11111111 11111111 11111111 11111111 - 补码
//11111111 11111111 11111111 11111111 - 结果 - 打印无符号数
//4294967295

int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}
//stelen函数当遇到'\0'时会停止统计字符串的长度
//char类型的数据的范围是[-128~127]
//因此我们可以猜测a的长度应该为255

-128 + (-1)
//10000000 00000000 00000000 10000000 - 原码
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000 - 补码
//10000000 截断 - a[i]
//11111111 11111111 11111111 10000000 整形提升

//11111111 11111111 11111111 11111111 - -1 - 补码

//11111111 11111111 11111111 10000000 - 补码 - -128
//11111111 11111111 11111111 11111111 - 补码 - -1
//00000000 00000000 00000000 01111111 - 补码 - 计算结果

//01111111 - a[i] - 截断

//00000000 00000000 00000000 01111111 - 补码 - 整形提升
//01111111 11111111 11111111 10000000
//00000000 00000000 00000000 01111111 - 原码 - 127
7.
    #include <stdio.h>
    unsigned char i = 0;
    int main()
    {
    for(i = 0;i<=255;i++)
    {
        printf("hello world\n");
    }
    return 0;
    }
//255 + 1
//00000000 00000000 00000000 11111111 - 255
//00000000 00000000 00000000 00000001 - 1

//00000000 00000000 00000001 00000000

//00000000 - 截断

//00000000 00000000 00000000 00000000 - 整形提升

关于浮点型在内存中的存储相关的内容,将在最近一段时间内继续补充完成。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 20:56:54  更:2022-10-22 21:01:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 4:02:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码