整数在内存中的存储和内存操作函数

news2024/10/7 14:33:02

目录

  • 整数在内存中的存储
    • 1. 整数在内存中的存储
    • 2. 大小端字节序和字节序判断
      • 2.1 什么是大小端?
      • 2.2 为什么有大小端
    • 3. 练习
      • 3.1 请简述大端字节序和小端字节序的概念,设计⼀个小程序来判断当前机器的字节序。(10分)-百度笔试题
      • 3.2 练习2
      • 3.3 练习3
      • 3.4 练习4
      • 3.5 练习5
  • 内存操作函数
    • 1. memcpy的使用和模拟实现
    • 2. memmove的使用和模拟实现
    • 3. memset函数的使用
    • 4.memcmp函数的使用


正文开始

整数在内存中的存储

1. 整数在内存中的存储

整数的2进制表示方法有三种,即 原码、反码和补码

有符号的整数,三种表式方法均有 符号位数值位 两部分,符号位都是用0表示“正”,用1表
示“负”,最高位的⼀位是被当做符号位,剩余的都是数值位。

正整数的原 , 反 , 补都相同
负整数的三种表示方法各不相同

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

为什么呢?

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

2. 大小端字节序和字节序判断

当我们了解了整数在内存中的存储后, 我们调试看一个细节:

#include <stdio.h>
int main()
{
	int a = 0x11223344;

	return 0;
}

调试的时候 , 我们可以看到在a中的 0x11223344 这个数字是按照字节为单位 , 倒着存储的 , 这是为什么呢?

在这里插入图片描述
通过上图我们可以发现:

  1. 整数在内存中的存储是二进制的补码
  2. 在调试窗口中观察内存的时候, 为了方便展示, 显示的是16进制的值
  3. 存储的顺序是倒过来的!

接下来让我们一起揭晓大小端字节序

2.1 什么是大小端?

其实超过一个字节的数据在内存中存储的时候, 就有存储顺序的问题 , 按照不同的存储顺序 , 我们可以分为大端字节序存储和小端字节序存储, 下面是具体概念:

大端存储模式:

是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处

小端存储模式:

是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。

上述概念需要记住, 方便分辨大小端

画图演示:

在这里插入图片描述

在这里插入图片描述

2.2 为什么有大小端

为什么要有大小端之分呢?

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为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处理器还可以由硬件来选择是⼤端模式还是⼩端模式。

3. 练习

3.1 请简述大端字节序和小端字节序的概念,设计⼀个小程序来判断当前机器的字节序。(10分)-百度笔试题

题目解析:

我们知道 , 对于一个16进制的1来说 , 0x00000001 在内存内存中的存储模式无非为以下俩种, 分别为大端字节序和小端字节序 , 此时我们只需要判断这个数字在内存中存储的第一个字节里面的内容即可 , 若为0则为大端字节序, 低位放在大地址处 , 若为1则为小端字节序存储 , 低位放在低地址处 , 由此我们可以进行代码实现 .
在这里插入图片描述

代码如下:


//代码一
#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;
}

//代码2 
int check_sys()
{
	union
	{
		int i;
		char c;
	}un;
	un.i = 1;
	return un.c;
}

3.2 练习2

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

试题分析:

第一步: 首先 -1在内存中如何存放的呢?

-1 原码为:
10000000 00000000 00000000 00000001
补码为(在内存中存放):
11111111 11111111 11111111 11111111

第二步: 放到a里面会发生截断只存储后八个bit位, 即
11111111 ->a
其实b也一样,c也一样
11111111 ->b
11111111 ->c

第三步:%d打印a , %d表示打印整数 , 而字符a需要进行整形提升之后进行打印 , a位-1 需要补符号位, 结果为
11111111 11111111 11111111 11111111 转化为原码打印结果为-1 , b也一样, 因为char变量在vs环境下默认为有符号char
而%d打印c , c也需要进行整形提升, 因为是无符号char所以默认为一个正数, 高位需要补0,结果为
00000000 00000000 00000000 11111111 , 因为是整数所以原码和补码结果一样 , 打印结果为255

代码运行:

在这里插入图片描述

对于有符号的char类型, 取值范围是: -128 ~ 127
在这里插入图片描述

对于无符号char的1取值范围是 0~255
在这里插入图片描述

3.3 练习3

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

试题分析:

有了刚才的基础作铺垫,
首先-128 的原码为 10000000 00000000 00000000 10000000 ,
反码为 11111111 11111111 11111111 01111111
补码为 11111111 11111111 11111111 10000000

存放在a里面要发生整形截断
10000000 ->a
%u表示打印无符号整形
此时需要整形提升 , 补符号位1
11111111 11111111 11111111 10000000
而%u表示打印一个无符号数, 默认原反补相同 , 所以打印结果仍然为
11111111 11111111 11111111 10000000
转换成十进制是一个很大的数

代码运行:

在这里插入图片描述

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

试题分析:

128 原码为:
00000000 00000000 00000000 10000000
因为是整数补码一样
存放在a中会进行截断, 存储内容为10000000

%u打印 先整形提升结果为
11111111 11111111 11111111 100000000
打印结果和上题一样

代码结果:

在这里插入图片描述

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

试题分析:
而这里我们采用%d打印结果 , 结果就是-128, 因为此时编译器会将整形提升的结果默认为补码, 而有符号为的补码需要转化为原码

代码结果:
在这里插入图片描述

3.4 练习4

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

试题分析:

求字符a的长度 , 也就是’\0’之前的内容 , 我们知道\0的ascll码值就是0, 也就是统计0之前的字符个数 , char型变量的存储范围为-128~127 , 首先我们来看下图 , 从00000000开始存储 , 到11111111的存储结果如下 , 而题目则是倒序, 即从-1倒序 ,
直到遇到0.其一个循环为255
在这里插入图片描述

代码运行:

在这里插入图片描述

3.5 练习5

#include <stdio.h>
//X86环境 ⼩端字节序 
int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);
	return 0;
}
//代码运行结构是啥?

试题分析: 指针+1 取决于指针类型
整数+1就是+1
此题便运用到了我们所学的整形的存储, 大小端字节序的问题,如图所示为小端字节序存储在内存中的分布, 首先&a即指向一个数组+1跳过一个数组, ptr1指向的位置如图所示, 强制转化为int* 类型, 而ptr1[-1], 即 * (ptr1-1),向前跳过一个字节, 指向的位置如图所示, 十六进制打印结果为4, 而a表示的是数组首元素的地址,转化为int整数类型,+1就是+1,即加上了一个字节, 而一个强制转化为int * , 而一个int占四个字节, 指向的位置如下图一所示, ptr2解引为0x02000000 ,因为为小端存储, 所以高地址为高位

在这里插入图片描述
代码运行:
在这里插入图片描述

内存操作函数

1. memcpy的使用和模拟实现

函数介绍:

void * memcpy ( void * destination, const void * source, size_t num );

• 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
• 这个函数在遇到 '\0' 的时候并不会停下来。
• 如果source和destination有任何的重叠,复制的结果都是未定义的。
#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

运行结果:

在这里插入图片描述

模拟实现:

#include<stdio.h>

void* memcpy(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	assert(dst);
	assert(src);
	
	while (count--) {
		*(char*)dst = *(char*)src;
		dst = (char*)dst + 1;
		src = (char*)src + 1;
	}
	return(ret);
}

2. memmove的使用和模拟实现

函数介绍:

void * memmove ( void * destination, const void * source, size_t num );

• 和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的。
• 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理
#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	} 
	return 0;
}

运行结果:

在这里插入图片描述

模拟实现:
分为以下两种情况: 从前往后复制和从后往前复制

在这里插入图片描述

#include<stdio.h>

void* memmove(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	if (dst <= src || (char*)dst >= ((char*)src + count)) {
		while (count--) {
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else {
		dst = (char*)dst + count - 1;
		src = (char*)src + count - 1;
		while (count--) {
			*(char*)dst = *(char*)src;
			dst = (char*)dst - 1;
			src = (char*)src - 1;
		}
	}
	return(ret);
}

3. memset函数的使用

函数介绍:

void * memset ( void * ptr, int value, size_t num );

memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。
#include <stdio.h>
#include <string.h>
int main ()
{
 char str[] = "hello world";
 memset (str,'x',6);
 printf(str);
 return 0;
}

代码结果:

1 xxxxxxworld

4.memcmp函数的使用

函数介绍:

1 int memcmp ( const void * ptr1, const void * ptr2, size_t num );

• ⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字
• 返回值如下

在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main()
{
	char buffer1[] = "DWgaOtP12df0";
	char buffer2[] = "DWGAOTP12DF0";
	int n;
	n = memcmp(buffer1, buffer2, sizeof(buffer1));
	if (n > 0)
		printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
	else if (n < 0)
		printf("'%s' is less than '%s'.\n", buffer1, buffer2);
	else
		printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
	return 0;
}

如有错误恳请指正, 感谢各位的点赞 收藏 !!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux三剑客-sed、awk、egrep(上)

一、知识梗概 二、正则表达式 定义&#xff1a;正则表达式是一种强大的文本处理工具&#xff0c;用于在文本中搜索符合特定模式的字符串。它由一系列特殊字符和普通字符组成&#xff0c;可以定义复杂的搜索模式。正则表达式被广泛应用于各种编程语言和文本处理工具中。 简单来…

【DNS】

文章目录 DNS域名解析系统&#xff08;Domain Name System&#xff09;DNS系统需要解决的问题DNS域名解析系统&#xff08;Domain Name System&#xff09;问题1&#xff1a;DNS名字空间(The DNS Name Space&#xff09;DNS名字空间(The DNS Name Space)DNS名字空间(The DNS Na…

解锁生成式 AI 的力量:a16z 提供的 16 个企业指南

企业构建和采购生成式AI方面的16项改变 生成式 AI 领域趋势洞察&#xff1a;企业构建和采购生成式 AI 的方式正在发生重大转变&#xff0c;具体表现在&#xff1a;* 专注于可信度和安全性&#xff1a;75% 的企业将信任和安全性视为关键因素。* 优先考虑可扩展性和灵活性&#x…

Go语言入门|包、关键字和标识符

目录 Go语言 包文件 规则 关键字 规则 标识符 规则 预定义标识符 Go语言 Go语言是一种静态类型、编译型和并发型的编程语言&#xff0c;由Google开发。Go的源代码文件以.go为扩展名&#xff0c;文件名通常与包名保持一致。一个Go文件可以包含多个顶级声明&#xff0c;…

WXML模板语法-条件与列表渲染

wx:if 在小程序中&#xff0c;使用wx:if"{{condition}}"来判断是否需要渲染该代码 也可以用wx:elif和wx:else来添加else判断 <!--pages/ifIndex/ifindex.wxml--> <view wx:if"{{type 1}}">男</view> <view wx:elif"{{type …

基于ICEEMDAN-SVD的信号去噪算法

一、代码原理 ICEEMDAN-SVD算法是一种结合了Improved Complete Ensemble Empirical Mode Decomposition with Adaptive Noise (ICEEMDAN) 和奇异值分解 (SVD) 的信号去噪方法。这种算法结合了两种先进的信号处理技术&#xff0c;旨在提高信号去噪的效果。以下是该算法的基本原…

深入理解信号上升沿与带宽的关系

信号的上升时间&#xff0c;对于理解信号完整性问题至关重要&#xff0c;高速pcb设计中的绝大多数问题都和它有关&#xff0c;很多信号完整性问题都是由信号上升时间短引起的&#xff0c;你必须对他足够重视。 信号上升时间并不是信号从低电平上升到高电平所经历的时间&#xf…

Ubuntu-22.04安装KVM虚拟机并安装Windows10

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、KVM是什么&#xff1f;二、安装步骤1.检查虚拟化2.查看KVM虚拟化3.安装KVM4.启用后台进程5.添加用户组6.重启电脑 三、使用步骤1.添加虚拟机2.配置虚拟机3.…

数据可视化高级技术Echarts(堆叠柱状图)

目录 一.如何实现 二.代码展示 1.stack名称相同&#xff08;直接堆叠&#xff09; 2. stack名称不相同&#xff08;相同的堆叠&#xff0c;不同的新生成一列&#xff09; 一.如何实现 数据堆叠&#xff0c;同个类目轴上系列配置相同的 stack 值可以堆叠放置。即在series中…

Rust取代C++? 保守了!关于未来的讨论

当各种平台在大肆讨论rust即将取代C/C的时候&#xff0c;已经有不少人意识到这种讨论是聒噪而无聊的。笔者和老师们通过周末茶会的讨论&#xff0c;认为现今世界常见的大多数编程语言都会在50-80年内被AI取代&#xff0c;同时供人类审计而诞生的“审计语言”会兴起。届时计算机…

LeetCode刷题记(三):61~90题

61. 旋转链表 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3]示例 2&#xff1a; 输入&#xff1a;head [0,1,2], k 4 输出&…

虚拟机VMware的下载、注册码(Mac与Windows)

1. 虚拟机的下载 windows 版的虚拟机叫 VMware Workstation mac版的虚拟机叫 VMware Fusion 官网下载地址: window 下载地址 https://www.vmware.com/content/vmware/vmware-published-sites/us/products/workstation-pro.html mac 下载地址 https://www.vmware.com/prod…

【ELFK】Filebeat+ELK 部署

FilebeatELK 部署 在 Filebeat 节点上操作 环境准备 Node1节点&#xff08;2C/4G&#xff09;&#xff1a;node1/192.168.67.11 Elasticsearch Kibana Node2节点&#xff08;2C/4G&#xff09;&#xff1a;node2/192.168.67.12 Elasticsearch Apache节点&…

解放双手,批量绕过403

将dirsearch扫描出来的结果复制到url.txt&#xff0c;如下所示 url.txt [21:18:16] 502 - 0B - /var/log/exception.log [21:18:21] 502 - 0B - /WEB-INF/jetty-env.xml [21:18:22] 502 - 0B - /WEB-INF/weblogic.xml [21:18:27] 502 - 0B - /wp-json/wp/v2/u…

【域适应】基于域分离网络的MNIST数据10分类典型方法实现

关于 大规模数据收集和注释的成本通常使得将机器学习算法应用于新任务或数据集变得异常昂贵。规避这一成本的一种方法是在合成数据上训练模型&#xff0c;其中自动提供注释。尽管它们很有吸引力&#xff0c;但此类模型通常无法从合成图像推广到真实图像&#xff0c;因此需要域…

Pandas相比Excel的优势是哪些?

熟悉Pandas的同学会知道&#xff0c;Pandas相当于Python中的Excel&#xff0c;都是基于二维表的进行数据处理分析&#xff0c;不同的是&#xff0c;Pandas基于代码操作数据&#xff0c;Excel是图形化的分析工具。 不少人会问Excel比Pandas更简单&#xff0c;为什么还要学习Pan…

SSL Pinning之双向认证

双向认证处理流程 概述获取证书逆向app 获取证书的KeyStore的 key通过jadx 反编译 app 获取证书&#xff1a;frida hook 证书转换命令行转换portecle 工具使用 charles 配置 p12 格式证书 概述 本篇只介绍怎么解决ssl pinning&#xff0c; 不讲ssl/tls 原理。 为了解决ssl pinn…

【Java】内存可见性问题是什么?

文章目录 内存模型内存可见性解决方案volatile 内存模型 什么是JAVA 内存模型&#xff1f; Java Memory Model (JAVA 内存模型&#xff09;是描述线程之间如何通过内存(memory)来进行交互。 具体说来&#xff0c; JVM中存在一个主存区&#xff08;Main Memory或Java Heap Mem…

MySQL优化慢SQL的6种方式

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《mysql经验总结》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途 目录 写在前面 优化思路 优化方法 1.避免查询不必要的列 2.分页优化 3.索引优化 4.JOIN优化 5.排序优化 6.UNION 优化…

基于51单片机多功能洗衣机控制(强洗弱洗漂洗)设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机多功能洗衣机控制(强洗弱洗漂洗)设计( proteus仿真程序设计报告原理图讲解视频&#xff09; 多功能洗衣机控制-强洗弱洗漂洗 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真设计4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单资料下载链接&#xf…