【C语言进阶】深度剖析数据在内存中的存储--上

1. C语言中的数据类型的简单介绍

注:C99标准里面,定义了bool类型变量。这时,只要引入头文件stdbool.h ,就能在C语言里面正常使用bool类型。

在这里插入图片描述
1.1 在C语言中各类型所占内存空间的大小如下

char类型的数据类型大小为1字节即8比特位。

short类型的数据类型大小为2字节即16比特位。

int类型、float类型的数据类型大小为4字节即32比特位。
long类型较为特殊,C语言规定中sizeof(long)>=sizeof(int)
32位平台下long大小为4字节,64位平台下long大小为8字节。
long long类型、double类型的数据类型大小为8字节即64位。

1.2 类型的意义:

  1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
  2. 如何看待内存空间的视角
    什么叫做看待内存空间的视角呢?以int类型、float类型为例,虽然大小都为4字节,但是存储的不同的数据类型。

1.3 类型的基本归类:
整型家族:

char类型在内存中以ASCLL码值存储,所以归类于整型家族
注:在C语言标准中,char类型默认为unsigned char 还是signed char是未定义的,取决于编译器,但是大部分编译器char默认为signed char
char

  unsigned char   signed char

short

unsigned short   signed short

int

int unsigned int   signed int

long

unsigned long   signed long

long long

unsigned long long   signed long long

有符号类型的最高位表示符号位,负数最高位是1,正数最高位是0。

浮点数家族:

float
double

构造类型:

数组类型

数组类型是去掉数组名,剩下的部分。
例如int arr1[5]和int arr2[8]两个数组的类型分别是int [5]和int [8].

结构体类型 struct
枚举类型 enum
联合类型 union

指针类型

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

空类型:

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

2. 整形在内存中的存储

我们知道数值有不同的表示方式.
例如十进制的21,用不同进制表示如下:
二进制表示:0b10101 (二进制以0b开头)
八进制表示:025 (八进制以0开头)
十六进制表示:0x15 (十六进制以0x开头)
而在计算机中数据是以2进制存储的。

2.1 原码、反码、补码

计算机中的整数有三种表示方法,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,
正整数的原码、反码、补码都相同。
负整数的三种表示方法各不相同。
原码 直接将二进制按照正负数的形式翻译成二进制就可以。
反码 将原码的符号位不变,其他位依次按位取反就可以得到了。
补码 反码+1就得到补码。

以正整数20和负整数10为例,原码反码补码如下。
数据在内存中是以二进制存储的,但为了方便程序员观察,在编译器的内存窗口显示的是16进制
在这里插入图片描述

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

2.2为什么要使用补码存储呢?

举个例子 计算机计算1-1是如何实现的呢,因为(CPU只有加法器)可以将1-1变为1+(-1) 假设都是短整型数据
1的原码是0000000000000001
-1的原码是1000000000000001
相加的结果是1000000000000010 //-2
1+(-1)的结果不应该是0么?这里的结果却是-2.
🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔
通过上面的例子我们可以看到,如果采用原码存储,不便于加减运算。无法直接得到计算结果。 而如果使用补码存储 假设都是短整型数据
1的补码是0000000000000001
-1的补码是111111111111111111
相加的结果是0000000000000000 // 0
通过上面的例子我们可以看到,如果采用补码存储,可以可以将符号位和数值域统 一处理,直接得到运算的结果。

补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路。
这句话是什么意思呢?

我们知道负整数的补码就是将原码的符号位不变,其他位依次按位取反再加1 那么知道了它的补码如何求源码呢?
将运算过程逆过来,负整数的补码-1就是反码,而反码再符号位不变,其他位按位取反就是原码,这是一种普遍的方法。
但是其实负整数的补码转换为原码也可以采用原码转换为补码时采用的方法 将补码符号位不变,其他位按位取反,再将得到的结果加1就是负整数的原码
例如-10的补码转换为原码:
在这里插入图片描述

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

2.3 大小端介绍

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

在这里插入图片描述

百度2015年系统工程师笔试题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
#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;
}

3.练习巩固

学习了上面诸多知识后,让我们来实践一下吧。

1.打印a,b,c的结果分别是什么?
注:signed char 取值范围-128~127 unsigned char取值范围0-255

#include <stdio.h>
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;
}

解析:

  char类型在vs编译器下默认是 signed char,将 -1存到signed char中会发生截断,-1默认是一个32位的整数。存到signed char中会截断低8位存储,所以a和b里存放的是11111111,而%d是打印有符号的整型数值,所以打印时会发生整型提升,提升时看a,b的类型,ab都是有符号类型,所以我们看它的最高位(符号位)来进行提升,这里的最高位是1,所以提升时在高位补24个1变为11111111111111111111111111111111,这时我们再将补码转换为原码1000000000000000000000000001得到的就是最终打印出来的结果的2进制序列,转换为10进制就是 -1,所以打印a,b的结果是 -1 .
  而c里存放的也是8个1,但是整型提升时因为是无符号类型,所以高位直接补24个0,凑齐32比特位。得到的补码是00000000000000000000000011111111,再将补码转换为原码依旧是00000000000000000000000011111111转换为10进制就是255,所以打印c的结果是 255。

2. 打印a的结果是什么?

#include <stdio.h>
int main()
{signed char a = -128;printf("%u\n",a);//%u打印无符号整数return 0;}

解析:
  -128的补码是11111111111111111111111110000000,截断低8位10000000,以%u形式打印发生整型提升,因为signed
char为有符号类型所以高位补符号位变为11111111111111111111111110000000,因为是以%u形式打印,所以会认为这串补码是一串非常大的正数的二进制序列,因为是正数所以补码原码相同,转换为10进制就是4294967168,所以a打印出来就是4294967168。

3.打印a的结果分别是是什么?

#include <stdio.h>
int main()
{signed char a = 128;printf("%u\n",a);  //4294967168printf("%d\n",a); //-128return 0;
}

答案: printf(“%u\n”,a); //4294967168
printf(“%d\n”,a); //-128

4…打印i的结果是什么?

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

答案:9 8 7 6 5 4 3 2 1 0 4294967295 4294967294 4294967293 …死循环下去
为什么结果会是这样呢? 解析: 因为i是一个无符号整数,所以9~0都是正常循环打印的,但是i–到了-1的时候,因为unsigned int
i是无符号整数,所以不会将-1的补码11111111111111111111111111111111看作是一个负数,而是会看作一个很大的正数,所以依旧满足循环条件。

在这里插入图片描述
5.字符串a的长度是多少?

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

解析:a[i]里存放的值依次是-1,-2,-3 …到-128为一个轮回,然后变为127,126
…2,1,0,然后再依次是-1,-2,-3
…一直循环到数组存满为止。本题求的是字符串长度,strlen在字符数组里找到‘\0’为止,而‘\0’的ascll码值为0,所以字符串a的长度是255。
在这里插入图片描述

6.下面代码的运行结果是什么?

#include <stdio.h>
unsigned char i = 0;
int main()
{for(i = 0;i<=255;i++){printf("hello world\n");}return 0;}

答案:无限打印hello world,死循环下去。
解析:无符号数到255后+1又会变为0,无限循环下去。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/468129.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[NSSCTF]-Web:[SWPUCTF 2021 新生赛]easyrce解析

先看网页 代码审计&#xff1a; error_reporting(0); &#xff1a;关闭报错&#xff0c;代码的错误将不会显示 highlight_file(__FILE__); &#xff1a;将当前文件的源代码显示出来 eval($_GET[url]); &#xff1a;将url的值作为php代码执行 解题&#xff1a; 题目既然允许…

ChatGPT高效提问—prompt实践(视频制作)

ChatGPT高效提问—prompt实践&#xff08;视频制作&#xff09; 1.1 视频制作 ​ 制作视频对于什么都不懂的小白来说非常难。而随着AI技术的发展&#xff0c;这件事变得越来越简单&#xff0c;如今小白也可以轻松上手。如何借助ChatGPT来制作短视频。 ​ 其实方法非常简单&a…

SolidWorks学习笔记——入门知识1

目录 1、固定最近文档 2、根据需要自定义菜单栏 3、根据需要增添选项卡 4、命令搜索框 5、鼠标右键长按快速切换视图 6、鼠标笔势 自定义鼠标笔势 1、固定最近文档 图1 固定最近文档 2、根据需要自定义菜单栏 图2 根据需要自定义菜单栏 3、根据需要增添选项卡 图3 根据…

javaspringbootMySQL高考志愿选择系统68335-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 第1章 绪论 1.1 研究背景与意义 1.2 研究现状 1.3论文结构与章节安排 第2章 相关技术 2.1开发技术 2.2 Java简介 2.3 MVVM模式 2.4 B/S结构 2.5 MySQL数据库 2.6 SpringBoot框架介绍 第3章 系统分析 3.1 可行性分析 3.2 系统流程分析 3.2.1 数…

【开源】SpringBoot框架开发企业项目合同信息系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 合同审批模块2.3 合同签订模块2.4 合同预警模块2.5 数据可视化模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 合同审批表3.2.2 合同签订表3.2.3 合同预警表 四、系统展示五、核心代码5.1 查询合同…

Java并发基础:DelayQueue全面解析!

内容概要 DelayQueue类专为处理延迟任务设计&#xff0c;它允许开发者将任务与指定的延迟时间关联&#xff0c;并在任务到期时自动处理&#xff0c;从而避免了不必要的轮询和资源浪费&#xff0c;此外&#xff0c;DelayQueue内部基于优先队列实现&#xff0c;确保最先到期的任…

2024年幻兽帕鲁服务器搭建方法_图文保姆级教程

幻兽帕鲁官方服务器不稳定&#xff1f;自己搭建幻兽帕鲁服务器&#xff0c;低延迟、稳定不卡&#xff0c;目前阿里云和腾讯云均推出幻兽帕鲁专用服务器&#xff0c;腾讯云直接提供幻兽帕鲁镜像系统&#xff0c;阿里云通过计算巢服务&#xff0c;均可以一键部署&#xff0c;鼠标…

【Jmeter】JDK及Jmeter的安装部署及简单配置

JDK的安装和环境变量配置 对于Linux、Mac和Windows系统&#xff0c;JDK的安装和环境变量配置方法略有不同。以下是针对这三种系统的详细步骤&#xff1a; 对于Linux系统&#xff1a; 下载适合Linux系统的JDK安装包&#xff0c;可以选择32位或64位的版本。 将JDK的安装包放置…

社区经营的好处与优势:为何越来越多的人选择社区店?

社区店&#xff0c;这个曾经被视为小型、局限的商业模式&#xff0c;如今正逐渐崭露头角&#xff0c;成为众多创业者和消费者的首选。 特别是在鲜奶吧这样的细分市场中&#xff0c;社区店更是展现出了其独特的魅力和优势。作为一名拥有五年鲜奶吧经营经验的创业者&#xff0c;…

【设计模式】springboot3项目整合模板方法深入理解设计模式之模板方法(Template Method)

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;底层原理高级进阶》 &#x1f680…

【国产MCU】-CH32V307-基本定时器(BCTM)

基本定时器(BCTM) 文章目录 基本定时器(BCTM)1、基本定时器(BCTM)介绍2、基本定时器驱动API介绍3、基本定时器使用实例CH32V307的基本定时器模块包含一个16 位可自动重装的定时器(TIM6和TIM7),用于计数和在更新新事件产生中断或DMA 请求。 本文将详细介绍如何使用CH32…

openssl3.2 - osslsigncode工程的学习

文章目录 openssl3.2 - osslsigncode工程的学习概述笔记工程库地址工程的编译osslsigncodeM工程文件列表osslsigncodeM工程搭建细节原始工程实现的改动自己封装的包含openssl和curl的实现osslsigncodeM工程命令行的用法备注 - VS2019调试环境备注 - 如果要单步openssl的API学学…