iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言数据在内存中的存储详解
  • 114
分享到

C语言数据在内存中的存储详解

2024-04-02 19:04:59 114人浏览 安东尼
摘要

目录文章摘要一、C语言的数据类型数据类型基本分为: 二、隐式类型转换1.什么是隐式类型转换2.整型提升 3.类型转换三、机器大小端1.什么是大小端2.大小端在截断的应用3.

文章摘要

本文通过内存底层原理,帮你透彻了解数据存储进内存与从内存中读取的区别以及不同数据类型下数据计算、赋值的变化情况
要透彻理解这些,必须知道隐式类型转换以及机器大小端的概念,本文会对此做简单介绍(这两个概念对C语言数据的深度理解非常重要)

一、C语言的数据类型

数据类型基本分为:

1.整性


char  //字符本质上是整型,只是char类型值截断开辟一个字节
	unsigned char
	signed char
short  //2字节
	unsigned short [int]
	signed short [int]
int  //4字节
	unsigned int
	signed int
long  //4字节
	unsigned long [int]
	signed long [int]

2.浮点型


float
double

3.构造类型


数组类型
结构体类型 struct
枚举类型 enum
联合类型 uNIOn

4.指针类型


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

5.空类型


void

二、隐式类型转换

1.什么是隐式类型转换

在C语言中,隐式类型转换是编译器自发的行为,它往往是从小到大的转换,在数据类型上表现是少字节数据类型,转换成多字节数据类型,保证数据的完整性;(面向对象语言也有该概念,并且对于类也会有隐式类型转换)一般来说,隐式类型转换大体分为两种:整性提升类型转换

2.整型提升 

1.定义: C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的 字符(char类型1字节) 和 短整型(short int类型2字节) 操作数在使用之前被转换为 普通整型(int类型4字节) ,这种转换称为整型提升。

通俗来说:无论数据类型是否为 char 、short int 、…,其在读取到CPU进行计算时,都会先通过整性提升到32位计算,而结算结果的读取位数取决于读取的数据类型,若为char类型,则截断取8位(bit).

【这里注意:通常CPU在计算时,用的数据是源码翻译后的补码来计算】

2.整性提升是按照变量的数据类型(指自身类型,而不是数值类型)的符号位来提升


//eg1.负数的整性提升
char a = -1;  //char类型默认为有符号类型
//其二进制源码为:1 000 0001
//        补码为:1 111 1111
//整性提升时,由于8bit的char类型数据中符号位为1;
//故提升为32位后 11111111 11111111 11111111 11111111;(补码)

//eg2.正数的整性提升
char a = 1; 
//其二进制源码为:0 000 0001
//   补码=源码为:0 000 0001
//整性提升时,由于8bit的char类型数据中符号位为0;
//故提升为32位后 00000000 00000000 00000000 00000001;(补码)

3.截断的具体体现:


//eg3.
char c = -129;
printf("%d",c);

结果为:127

原因是:-129源码为:1000 0000 0000 0000 0000 0000 1000 0001

在内存中的补码为:1111 1111 1111 1111 1111 1111 0111 1111

而字符变量c 只截断8bit位 即c变量保存的是:0111 1111(补码)

输出d%位整型,且符号位为0

整型提升为0000 0000 0000 0000 0000 0000 0111 1111(补码)

转为源码即为127

注意这里的截断原则与机器大小端有关,且截断是在内存上对补码进行操作

3.类型转换

1.概念:操作符两边的操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行;而这种转换就是类型转换(编译器自发)

2.从下至上,自动转换


long double
double
float
unsigned long int
long int
unsigned int
int

3.【注意】这种类型转换只是建立在运算操作符之间,不然会出现不合理问题


eg4.
float f = 3.14;
int num = f;//隐式转换,会有精度丢失

赋值情况下导致在高位的float类型转为低位的int类型,导致精度丢失

三、机器大小端

1.什么是大小端

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

大多数机器都采用小端模式

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

2.大小端在截断的应用

上文的eg3.中出现了截断,即字符c截断整型数值-129


//eg3.
char c = -129;

在这里插入图片描述

我们将代码中的整型a变量在内存的地址储存数据显示出来,从内存地址可以看出,序列从高到低递增
a:补码为 1111 1111 1111 1111 1111 1111 0111 1111

转为16进制后即为 ff ff ff 7f;(权值左边最高,右边最低

再将字符变量c内存的地址储存数据显示出来,可以看出,由于char类型只有一字节,会优先从四字节a中截断地址最低的一字节

由图看出它截断了低地址里的数据7f,而7f也是低权值。
故,在vs2013中,采用的是小端原则

3.判断当前机器的字节序是大端还是小端


#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)

int check_sys()
{
	int i = 1;
	return (*(char*)&i);//注意,发生数据类型转换
}

int main()
{
	int ret = check_sys();
	if (ret)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}

	system("pause");
	return 0;
}

【注意】(*(char*)&i);

这里是对指针的解引用时,从内存所取的字节大小由其指向的数据类型决定。 说白了就是 i 的地址从int *被强转为char *,再解引用时,其指向的数据类型从int变为char,因此显示的数据会发生截断;

由上面的截断方式我们可以知道,1在内存是以32位存储的,按一字节来说,其高权值位为0、低权值位为1.故可以通过return传参的1或0判断大小端。

四、整型在内存中的存储

 1.原码、反码、补码

一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011;

如果是 -3 ,就是 10000011

在C语言中,整型在计算机的储存情况是按原反补的规则储存,即对于整型来说,数据存放在内存中其实是补码。

计算机采用这种规则可以使数据运算时的+ - * / 运算都通过加法解决,这样设计的计算机只需设计出加法模块,大大节省成本。

具体规则如下:

1.正数

正数的原、反、补码都相同,与原码一样

2.负数

原码:该数的机器数,最高位为符号位

反码:原码除符号位不变,其余位按位取反

补码:反码+1 

2.举例实践整型数据在内存的存储


//例1.尝试判断输出结果是什么
int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d\n", a, b, c);

	system("pause");
	return 0;
}

结果:

在这里插入图片描述

例1解析:

-1在内存的补码:1111 1111 1111 1111 1111 1111 1111 1111

char a 、signed char b 、unsigned char c 存放时发生截断,其在内存的补码均为:1111 1111

但是三位在以%d(整型)输出时,会发生整型提升由原来的8位整型提升到32位,而整型提升时高位补0还是补1需看数据自身类型(有符号类型补符号位,无符号类型直接补0

char a 与 signed char b 均属于有符号型,且符号位为1,补24位1

内存数值为:1111 1111 1111 1111 1111 1111 1111 1111;输出%d时反向推回原码,答案即为 -1

unsigned char c 属于无符号型,补24位0

内存数值为:0000 0000 0000 0000 0000 0000 1111 1111;输出%d时反向推回原码,答案即为 255


//例2.尝试判断输出结果是什么
int main()
{
	char a = 128;
	char b = -128;
	printf("a=%u,b=%u\n", a,b);
	
	system("pause");
	return 0;
}

结果:

在这里插入图片描述

例2解析:

128在内存的补码:0000 0000 0000 0000 0000 0000 1000 0000

-128的内存补码: 1111 1111 1111 1111 1111 1111 1000 0000

char a 、char b 存放时发生截断,其在内存的补码均为:1000 0000

%u(无符号整型)输出时,会发生整型提升由原来的8位整型提升到32位

char a 与 char b 均属于有符号型,且符号位为1,补24位1

内存数值均为:1111 1111 1111 1111 1111 1111 1000 0000;输出%u时反码直接当原码,

答案即为 :

在这里插入图片描述


//例3.尝试判断输出结果是什么
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("i+j = %d\n", i + j);
	
	system("pause");
	return 0;
}

结果:

在这里插入图片描述

例3解析:

-20在内存的补码:1111 1111 1111 1111 1111 1111 1110 1100

10在内存的补码:0000 0000 0000 0000 0000 0000 0000 1010

int i 与 unsigned int j 都是四字节类型变量故存储时不会发生截断,

但 ·i + j = 表达式会发生类型转换,int 会自动转换为 unsigned int 类型计算

CPU中将两变量补码进行相加得到:1111 1111 1111 1111 1111 1111 1111 0110

计算结果以%d(整型)输出,反向推回原码:1000 0000 0000 0000 0000 0000 0000 1010

答案即为 -10


//例4.尝试判断输出结果是什么
int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}

	system("pause");
	return 0;
}

结果:

在这里插入图片描述

例4解析:

由于 i 变量时 unsinged int 类型,因此其无符号位,

且 ·i >= 0 表达式会发生类型转换,int 0 会自动转换为 unsigned int 类型计算

故其比较结果永远为真,因为无符号类型第32bit位(符号位)永远为0

for 循环条件永远满族,答案即为死循环


//例5.尝试判断输出结果是什么
int main()
{
	char a[1000];
	int i;
	for (i = 0; i <1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d\n", strlen(a));

	system("pause");
	return 0;
}

结果:

在这里插入图片描述

例5解析:

char a[1000]数组的每一位元素都是1字节的 char 类型,有字符位,故其保存的数值范围:[-128,127];

-1-i 范围从 -1到 -1000,但在循环体 a[i] = -1 - i中每次赋值都会发生截断,由下图可知,char类型保存的数值依次递减时,-1 继续减到 -128 ,128 减一位到 127,127 继续减到0,0再减一位到 -1,继续下一轮循环;

在这里插入图片描述

而该题的输出时数组字符长度,strlen遇 ‘\0'(等价于数值0),而在初始化后的char a[1000]数组中,数值第一次出现0在a[255];

故答案为255


//例6.尝试判断输出结果是什么
int main()
{
	unsigned char i = 0;
	for (i = 0; i <= 255; i++)
	{
		printf("%d ", i);
		Sleep(30);
	}

	system("pause");
	return 0;
}

结果:0-255无限循环

在这里插入图片描述

例6解析:

由例5解析的图可知:unsigned char 类型的变量 i 的取值范围:[-128,127],永远小于255;

而%d输出时,无符号类型直接整型提升补24位0:

0000 0000 (0)转为 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000(补),补码转原码:符号位为0,原码与补码一样,值为0;

1000 0000(-128)转为0000 0000 0000 0000 0000 0000 0000 0000 1000 0000(补),补码转原码:1000 0000 0000 0000 0000 0000 1000 0000,值为128;

0111 1111(127)转为0000 0000 0000 0000 0000 0000 0000 0111 1111(补),补码转原码:符号位为0,原码与补码一样,值为127

由此可知,无符号字符类型变量整型提升后再%d输出没有负数

故答案为:0-255循环

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: C语言数据在内存中的存储详解

本文链接: https://www.lsjlt.com/news/137002.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言数据在内存中的存储详解
    目录文章摘要一、C语言的数据类型数据类型基本分为: 二、隐式类型转换1.什么是隐式类型转换2.整型提升 3.类型转换三、机器大小端1.什么是大小端2.大小端在截断的应用3....
    99+
    2024-04-02
  • C语言编程数据在内存中的存储详解
    目录变量在计算机中有三种表示方式,原码反码,补码原码反码补码总结一下浮点数在内存的储存C语言中,有几种基本内置类型。 int unsigned int signed int cha...
    99+
    2024-04-02
  • 关于C语言中数据在内存中的存储详解
    目录前言一、数据类型介绍1.类型的基本归类1.整形家族2.浮点型家族3.构造类型4.指针类型5.空类型二、整型在内存中的存储1.原码、反码、补码2.内存中怎样存储3.大小端字节序1....
    99+
    2024-04-02
  • C语言数据在内存中的存储
    这篇文章主要介绍了C语言数据在内存中的存储,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。数据类型详细介绍在前面C语言基础概览中,已经提到过了基本的C语言内置类型,但C语言的数...
    99+
    2023-06-15
  • C语言中数据在内存如何存储
    目录数据类型类型的基本归类整形有符号数和无符号数是否char 等于signed char呢?浮点型构造类型(自定义类型)指针类型空类型整形在内存中的存储原码,反码,补码正整数负整数大...
    99+
    2024-04-02
  • 详解C语言中数据的存储
    目录一、类型归类1、整形家族2、浮点型家族3、指针类型4、空类型二、类型的意义 三、数据在类型中存储(以整形和浮点型为例子)1. 关于 存储的基本概念2.存储模式四.应用1.2.对...
    99+
    2024-04-02
  • C语言中数据的存储详解
    目录1.内置类型(1)整型数组(2)浮点型2.自定义类型3.指针类型4.空类型(void)字符型浮点型(一)(二)总结 数据的存储首先就要说到数据的类型,类型决定了看待内存空间的视角...
    99+
    2024-04-02
  • C语言数据在内存中是怎样存储的
    这篇文章主要介绍“C语言数据在内存中是怎样存储的”,在日常操作中,相信很多人在C语言数据在内存中是怎样存储的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言数据在内存中是怎样存储的”的疑惑有所帮助!接下来...
    99+
    2023-06-08
  • C语言数据存储详解
    目录一、数据类型二、整型在内存中的存储1.原码、反码、补码大小端介绍三、浮点型在内存中的存储1.举一个浮点数存储的例子: 2.浮点数存储规则: 总结一、数据类型 char:字符数字类...
    99+
    2024-04-02
  • C语言数据的存储详解
    目录数据类型的介绍整形浮点型构造类型指针类型void空类型整数在内存中的存储原反补的介绍大小端的介绍面试例题练习浮点数在内存中的存储存储规则讲解举例IEEE754的特别规定案例flo...
    99+
    2024-04-02
  • C语言中数据在内存中是怎么存储的
    本篇文章为大家展示了C语言中数据在内存中是怎么存储的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。数据类型常见的数据类型常见的数据类型字节char字符数据类型1short短整型2int整形4long...
    99+
    2023-06-22
  • C语言中数据是如何存储在内存中的
    目录前言‍数据类型介绍‍整形数据在内存中存储‍浮点型数据在内存存储前言 在计算机内存中,数据的存储方式都是以0和1的形式存储,也就是二进制的形式,数据是如何向...
    99+
    2024-04-02
  • C语言数据(整数、浮点数)在内存中的存储
    本篇主要讨论:整数、浮点数在内存中是怎么保存的! 数据类型详细介绍 在前面C语言基础概览中,已经提到过了基本的C语言内置类型,但C语言的数据类型有无数种~ 但是可以把这些类型分为几个...
    99+
    2024-04-02
  • C语言详细分析浮点数在内存中的储存
    目录浮点数的储存格式初步了解深入探究E不全为0或不全为1E全为0E全为1浮点数的储存格式 初步了解 首先让我们通过一段代码来认识一下浮点型和整型的区别: int main() { ...
    99+
    2024-04-02
  • C语言详解float类型在内存中的存储方式
    目录1.例子2.浮点数存储规则1.例子 int main() { int n = 9; float *pFloat = (float *)&n; ...
    99+
    2024-04-02
  • C语言数据的存储超详细讲解下篇浮点型在内存中的存取
    目录前言浮点型在内存中的存储浮点数存储的例子浮点数存储规则IEEE 754规定IEEE 754对有效数字M的特别规定IEEE 754对指数E的特别规定存入内存是E的规定从内存取出时E...
    99+
    2024-04-02
  • C++浮点数在内存中的存储详解
    目录前言:浮点数的表示形式浮点数存储模型有效数字M指数E例题讲解总结前言: 我们在码代码的时候,经常遇到过以整数形式存入,浮点数形式输出;或者浮点数形式存入整数形式输出。输出的结果往...
    99+
    2024-04-02
  • C语言数据在内存中的存储流程深入分析
    目录前言类型的基本分类整型浮点数自定义类型整型在内存中的存储原码、反码、补码大端和小端如何判断编译器是大端还是小端浮点数在内存中的存储总结前言 C语言中有char、short、int...
    99+
    2022-11-13
    C语言数据在内存中的存储 C语言数据存储
  • C语言浮点型数据在内存中的存储方式是什么
    本篇内容介绍了“C语言浮点型数据在内存中的存储方式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、思考一下咱们先上一盘开胃菜,试试看...
    99+
    2023-07-05
  • 深度解析C语言中数据的存储
    目录前言数据类型介绍类型的基本归类整型家族浮点数家族构造类型指针类型空类型前言 在VS编译器里有release和debug两种形式,debug包含调试信息,release不包含调试信...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作