C语言——小细节和小知识9
一、大小端字节序
1、介绍
在计算机系统中,大小端(Endianness)是指多字节数据的存储和读取顺序。它是数据在内存中如何排列的问题,特别是与字节顺序相关。C语言中的数据存储大小端字节序指的是在内存中存储的多字节数据类型(如整型、浮点型)的字节序排列方式,主要有两种:
-
大端字节序(Big-Endian):在大端字节序中,一个多字节数据的最高有效字节(即“大端”)存储在内存的最低地址处,其余字节按照在数值中的顺序依中次存储在连续的内存地址。例如,一个四字节的整数
0x12345678
在内存中的存储顺序(从低地址到高地址)为12 34 56 78
。 -
小端字节序(Little-Endian):在小端字节序中,一个多字节数据的最低有效字节(即“小端”)存储在内存的最低地址处,其余字节按照在数值中的逆序存储在连续的内存地址中。采用同样的四字节整数
0x12345678
为例,在内存中的存储顺序(从低地址到高地址)将会是78 56 34 12
。
大小端字节序通常由硬件决定,即由CPU的设计来规定。例如,Intel的x86架构是小端字节序,而网络协议通常采用大端字节序。在C语言编程中,通常不需要关心数据的字节序,除非你在进行底层的内存操作或者网络通信、跨平台数据传输等需要考虑字节序兼容性的场合。在这些情况下,你可能需要使用函数如 htonl()
和 ntohl()
来在主机字节序和网络字节序之间转换整数类型的数据。
目前,大部分的个人电脑和服务器处理器采用小端(Little-Endian)字节序。这主要是因为Intel的x86架构处理器和后续的x86-64架构(也称为AMD64)都采用小端字节序,而这些处理器在个人电脑和服务器市场中占据主导地位。
除了Intel和AMD之外,许多基于ARM架构的处理器也通常配置为小端模式,尤其是在智能手机和平板电脑等移动设备中。ARM架构是可切换的,即可以在大端和小端之间切换,但在实际应用中,小端模式更为普遍。
大端(Big-Endian)字节序相对来说较少见,但在某些应用和处理器设计中仍然使用,例如在一些嵌入式系统、网络设备和早期的IBM、Sun等公司的系统中。网络协议,如IP协议,使用的是大端字节序,这通常称为网络字节序。
随着市场的发展和技术的演进,小端字节序成为了主流,但在进行跨平台或网络编程时,处理字节序依然非常重要。在这些领域,开发者必须确保数据在不同字节序的系统间正确传输和解释。
2、例子
以下程序的运行结果:
#include <stdio.h>int main()
{int arr[] = { 1,2,3,4,5 };short* p = (short*)arr;int i = 0;for (i = 0; i < 5; i++){*(p + i) = 0;}for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;
}
在运行后,我们发现运行结果是:
这就可以证明这里是小端字节序。
3、分析
数组中元素内容用十六进制表示是:
为什么可以表示成这样呢?实际上可以这样解释:
这是因为一个十六进制数的单个位可以表示4位二进制数的值。换句话说,十六进制数的每一位相当于二进制数的一个四位组(nibble),即:
0
二进制表示为0000
1
二进制表示为0001
2
二进制表示为0010
- ...
E
二进制表示为1110
F
二进制表示为1111
十六进制的一位可以表示0 ~ 15这16个数字,而16是2 ^ 4,在二进制下,四位二进制数恰好可以表示0000 ~1111这16个数字,(这里我们可以这样理解,四位二进制数字,每一位有两种状数字,即0或1,而这里有四位,所以总共可表示的数字是2 * 2 * 2 * 2中,即2 ^ 4个数字,也就是16个数字),所以可以可以用一位十六进制数字表示四位二进制数字。
所以,一个两位的十六进制数,可以表示两个四位组,即8位二进制,这正好是一个字节(1 Byte)的大小。例如:
- 十六进制的
00
表示二进制的0000 0000
- 十六进制的
01
表示二进制的0000 0001
- 十六进制的
FF
表示二进制的1111 1111
最开始数组的存储是这样的:
由于int的大小为4字节,而short类型是2字节,在经过强制转换后,再通过一个循环对数组的内容进行更改:
从这里我们可以发现这里使用的是小端字节序,因为这里打印时第三个数据是0,如果是大端字节序,则第三个元素应当还是3。
二、整型的首地址
1、介绍
如果整型数据是以小端字节序(Little-Endian)存储的,那么该数据的首地址会指向这个整型数据的最低有效字节。换句话说,整型数据的首个字节(存储在首地址处的字节)包含了这个数值的最低位部分。
这意味着,如果我们有一个32位的整型数值 0x12345678
,并且我们的系统是小端字节序,那么在内存中的布局将从首地址开始按照下列方式存储:
Memory Address Value
0x0000 0x78 // 最低有效字节 (LSB)
0x0001 0x56
0x0002 0x34
0x0003 0x12 // 最高有效字节 (MSB)
在这种情况下,首地址 0x0000
指向的是值 0x78
,这是这个整型数值的最低有效字节。
如果整型数据是以大端字节序(Big-Endian)存储的,那么该数据的首地址会指向这个整型数据的最高有效字节。换句话说,在大端字节序中,整型数据的首个字节(存储在首地址处的字节)包含了这个数值的最高位部分。
例如,考虑相同的32位整型数值 0x12345678
。如果我们的系统采用大端字节序,那么在内存中的布局将从首地址开始按照如下方式存储:
Memory Address Value
0x0000 0x12 // 最高有效字节 (MSB)
0x0001 0x34
0x0002 0x56
0x0003 0x78 // 最低有效字节 (LSB)
在这个例子中,首地址 0x0000
指向的是值 0x12
,这是这个整型数值的最高有效字节。这和小端字节序相对,小端字节序的首地址指向最低有效字节。
所以对于两种字节序,实际上整型的首地址都是较低的地址。
2、例子
#include <stdio.h>int main()
{int a = 0x11223344;char* pa = (char*)&a;*pa = 0;printf("%x\n", a);return 0;
}
这个程序的运行结果是:
3、分析
因为整型数据首地址是较低的地址,又因为这里是小端字节序,所以a在内存中的存储是:
由于char类型的数据是1字节,所以在用char *类型指针访问a的时候只能访问到a的首地址中的数据,所以只能更改a首地址指向的内存中的数据,这样就只有一个字节的数据被改动。
所以得到了那样的结果。
三、gets_s函数
1、介绍
我们在需要获取标准输入流中的内容时,一般是用scanf()函数,我们知道在要读取一个字符串时,可以用:
char arr[10001];scanf("%s", arr);
但是我们也知道scanf在读取到空格和换行时会停止读取或进行下一个数据的读取不会将空格和数据读到一个缓冲区中。这就导致如果我们要读取一个完整的英文句子例如:
i love you.
就不能用scanf函数。
然而实际上我们可以用别的函数解决这个问题,那就是gets,这里会有人问了,你的标题不是gets_s么,怎么又变成了gets了?
实际上gets是gets_s的老版本,gets
函数因为安全性问题已经在C11标准中被废弃,并在C17标准中被彻底移除。gets
函数不检查目标缓冲区的长度,因此非常容易造成缓冲区溢出,这是一个严重的安全漏洞。
gets_s
是 gets
的一个安全版本,定义在 <stdio.h>
头文件中,并且它要求调用者提供缓冲区的大小,以避免超出缓冲区边界的写入,因为超出缓冲区可能导致缓冲区溢出攻击或程序崩溃。
函数原型如下:
char *gets_s(char *str, rsize_t n);
这里:
str
是指向用来存储输入字符串的字符数组的指针。n
是str
中可以存储字符的最大数量,包括结尾的空字符('\0'
)。
如果读取成功,gets_s
会从标准输入读取一行直到遇到换行符或EOF(文件结束符)。换行符不会被复制到数组中,数组会以空字符结尾。
注意,gets_s
函数是可选的,因此不是所有支持C11标准的编译器都实现了这个函数。在实际使用中应该检查你的开发环境是否支持它。
gets_s
的返回值为:
- 如果成功,返回一个指向
str
的指针。 - 如果遇到错误或文件结束而没有读取任何字符,返回
NULL
。
使用 gets_s
时需要特别小心,即使它比 gets
更安全。你需要确保你传递的 n
值不大于分配给 str
的实际内存大小。即使 gets_s
会检查这个大小,但如果你的大小参数错误,这可能会导致未定义行为。另外,建议避免使用 gets
和 gets_s
,而是使用 fgets
,因为 fgets
在所有标准的C库中都是可用的,并且也允许你指定缓冲区大小。
2、例子
#include <stdio.h>int main()
{char buffer[20] = { '\0' };gets_s(buffer, 20);printf("%s\n", buffer);return 0;
}
运行结果:
这里结果只有一个换行,是printf函数中的\n而不是gets_s读取的回车,因为gets_s函数不会将换行符复制到数组中。
四、fgets函数
1、介绍
上面提到了fgets函数使用更广泛,那具体是怎么使用的呢?
fgets
函数是一个在C语言中广泛使用的标准库函数,用于从文件流中读取一行。
fgets
函数的原型定义在 <stdio.h>
头文件中,如下所示:
char *fgets(char *str, int num, FILE *stream);
参数说明:
str
:指向一个字符数组的指针,这个数组用来存储读取的字符串。num
:指定要读取的最大字符数,包括最后的空字符('\0'
)。简单来说,如果缓冲区大小为n
,那么最多读取n-1
个字符,保证有空间放置字符串结尾的空字符。stream
:要读取的输入流,通常是文件指针。如果你想从标准输入(通常是键盘)读取,可以使用stdin
作为这个参数。
又有人会问了,为什么上面的gets_s函数的字符串最大存储数(包括' \0 ')的类型是rsize_t,而这里的fgets函数的是int类型?
gets_s
和 fgets
函数的参数类型不同,这主要是因为它们分别遵循了C的不同标准,并且设计上考虑了不同的安全性和可移植性问题。
gets_s
是在C11标准中引入的安全版本的gets
函数。其参数类型 rsize_t
是一种在C11中定义的新的类型。这个类型用于表示对象的大小,是一个无符号的整数类型,并且是为了增强程序的安全性和可移植性。rsize_t
的使用意味着gets_s
函数的缓冲区大小参数不应该为负数。
char *gets_s(char *s, rsize_t n);
另一方面,fgets
函数存在的时间要比gets_s
长得多,它是在之前的C标准中定义的,包括ANSI C和C99,这些标准中没有rsize_t
类型。在fgets
的定义中,其缓冲区大小参数是int
类型,这已经被广泛使用并且在各种C编译器和平台中都得到了支持。
char *fgets(char *str, int n, FILE *stream);
虽然从理论上讲,int
类型可以接受负数,但在fgets
的上下文中,传递一个负数没有逻辑意义,因为它代表了缓冲区的大小。实际上,如果调用fgets
时传入了一个负数,函数的行为将是未定义的。
总的来说,rsize_t
的使用提供了更强的类型安全性,强调了函数参数应当是一个合理的大小值。而fgets
使用int
是因为它遵循了旧的标准,而那时候没有为了表示大小而专门设立的无符号类型。在实际使用中,你应该总是传入正数作为这些函数的大小参数。
fgets
会从指定的 stream
读取字符,直到发生以下三种情况之一:
- 读取了
num-1
个字符。 - 读取到了一个换行符,换行符会被存储在字符串中。
- 遇到了文件结束符(EOF)。
在字符串的末尾,无论是因为读取到了换行符还是因为达到了字符数量限制,fgets
总是会在最后添加一个空字符('\0'
)来表示字符串的结束。
fgets
的返回值:
- 成功:返回
str
的指针。 - 失败或遇到文件结束符而没有读取任何字符:返回
NULL
。
由于 fgets
包括换行符在内的读取方式,因此通常在使用 fgets
后需要检查并处理字符串末尾可能存在的换行符。
2、例子
#include <stdio.h>int main()
{char buffer[20] = { '\0' };fgets(buffer, 20, stdin);printf("%s\n", buffer);return 0;
}
运行结果:
这里结果有两行换行,因为fgets函数会将换行符复制到数组中,再加上printf中的\n,刚好有两个换行。
相关文章:

C语言——小细节和小知识9
一、大小端字节序 1、介绍 在计算机系统中,大小端(Endianness)是指多字节数据的存储和读取顺序。它是数据在内存中如何排列的问题,特别是与字节顺序相关。C语言中的数据存储大小端字节序指的是在内存中存储的多字节数据类型&…...
uni-app基础详解(组件、弹窗、数据缓存、页面跳转)
uni-app基础详解(组件、弹窗、数据缓存、页面跳转) uni-app组件scroll-viewswipertext 文本button 按钮input 输入框radio 单选checkbox 多选picker 选择器slider 滑块textarea 文本域 弹窗提示框 uni.showLoading提示弹窗 uni.showToast确定取消框 uni.…...

LabVIEW模拟荧光显微管滑动实验
LabVIEW模拟荧光显微管滑动实验 在现代生物医学研究中,对微观生物过程的精准模拟和观察至关重要。本案例展示了如何利用LabVIEW软件和专业硬件平台,创新地模拟荧光显微管在滑动实验中的动态行为,这一过程不仅提升了实验效率,还为…...
Springboot项目:解决@Async注解获取不到上下文信息问题
问题描述 springboot项目中,需要使用到异步调用某个方法,此时 第一个想到的就是 Async 注解,但是 发现 方法执行报错了,具体报错如下: java.lang.NullPointerExceptionat com.ruoyi.common.utils.ServletUtils.getRe…...

国内镜像:极速下载编译WebRTC源码(For Android/Linux/IOS)(二十四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...
ThinkPHP为什么用PHP+Swoole协程模式部署运行
看很多ThinkPHP框架的程序商城等系统,现在都用PHPSwoole协程来运行。在说Swoole前我们先了解下传统PHP模式。 PHP-FPM 的对象常驻内存问题 互联网发展早期,大部分项目的业务逻辑并没有那么复杂,技术生态相对比较简单,也没有 Com…...

Vulnhub-tr0ll-1
一、信息收集 端口收集 PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.2 | ftp-anon: Anonymous FTP login allowed (FTP code 230) |_-rwxrwxrwx 1 1000 0 8068 Aug 09 2014 lol.pcap [NSE: writeable] | ftp-syst: | STAT: | FTP …...

服务器和电脑有啥区别?
服务器可以说是“高配的电脑”,两者都有CPU、硬盘、电源等基础硬件组成,但服务器和电脑也是有一定区别的,让小编带大家了解一下吧! #秋天生活图鉴# 1、稳定性需求不同:服务器是全年无休,需要高稳定性&…...

C语言——编译和链接
(图片由AI生成) 0.前言 C语言是最受欢迎的编程语言之一,以其接近硬件的能力和高效性而闻名。理解C语言的编译和链接过程对于深入了解其运行原理至关重要。本文将详细介绍C语言的翻译环境和运行环境,重点关注编译和链接的各个阶段…...

Kubernetes (K8S) 3 小时快速上手 + 实践
1. Kubernetes 简介 k8s即Kubernetes。其为google开发来被用于容器管理的开源应用程序,可帮助创建和管理应用程序的容器化。用一个的例子来描述:"当虚拟化容器Docker有太多要管理的时候,手动管理就会很麻烦,于是我们便可以通…...

如何画出优秀的系统架构图-架构师系列-学习总结
--- 后之视今,亦犹今之视昔! 目录 早期系统架构图 早期系统架构视图 41视图解读 41架构视图缺点 现代系统架构图的指导实践 业务架构 例子 使用场景 画图技巧 客户端架构、前端架构 例子 使用场景 画图技巧 系统架构 例子 定义 使用场…...
VR转接器:打破界限,畅享虚拟现实
你是否曾梦想过踏入另一个世界,体验那种仿佛置身其中的感觉?随着科技的飞速发展,虚拟现实(VR)已经成为了现实。而VR转接器,正是让你畅享虚拟现实的关键所在。 添加图片注释,不超过 140 字&…...

C++学习笔记——用C++实现树(区别于C)
树是一种非常重要的数据结构,它在计算机科学中的应用非常广泛。在本篇博客中,我们将介绍树的基本概念和C中如何实现树。 目录 一、树的基本概念 2.C中实现树 2.1创建一个树的实例,并向其添加节点 2.2三种遍历方式的实现代码 3.与C语言相…...

工业平板定制方案_基于联发科、紫光展锐平台的工业平板电脑方案
工业平板主板采用联发科MT6762平台方案,搭载Android 11.0操作系统, 主频最高2.0GHz,效能有大幅提升;采用12nm先进工艺,具有低功耗高性能的特点。 该工业平板主板搭载了IMG GE8320图形处理器,最高主频为680MHz, 支持108…...
JPA查询PostgreSQL行排序问题
文章目录 问题处理PostgreSQL排序相关JPA相关介绍 问题 我们项目使用Spring Boot构建,使用JHipster生成业务代码,包含基础的增删改查代码使用PostgreSQL作为业务数据库,使用自动生成的JPA构建数据更新语查询在查询某个实体类的列表时&#x…...

【css】渐变效果
css渐变效果 使用 CSS 渐变可以在两种颜色间制造出平滑的渐变效果。 用它代替图片,可以加快页面的载入时间、减小带宽占用。同时,因为渐变是由浏览器直接生成的,它在页面缩放时的效果比图片更好,因此你可以更加灵活、便捷的调整页…...

Maven 依赖传递和冲突、继承和聚合
一、依赖传递和冲突 1.1 Maven 依赖传递特性 1.1.1 概念 假如有三个 Maven 项目 A、B 和 C,其中项目 A 依赖 B,项目 B 依赖 C。那么我们可以说 A 依赖 C。也就是说,依赖的关系为:A—>B—>C, 那么我们执行项目 …...

Linux Centos7静默安装(非图形安装)Oracle RAC 11gR2(Oracle RAC 11.2.0.4)
Oracle RAC (全称Oracle Real Application Clusters )静默安装(非图形安装)教程。 由于这篇文章花费了我太多时间,设置了仅粉丝可见,见谅。 环境说明: 虚拟机软件:VMware Workstation 16 Pro…...
集成开发环境(IDE)介绍
集成开发环境(IDE)介绍 集成开发环境(Integrated Development Environment,IDE)是一种软件应用程序,用于开发和编写软件。常见的IDE包括Eclipse、Visual Studio、IntelliJ IDEA、Qt Creator等。 集成开发环…...

基于物联网设计的智能储物柜(4G+华为云IOT+微信小程序)
一、项目介绍 在游乐场、商场、景区等人流量较大的地方,往往存在用户需要临时存放物品的情况,例如行李箱、外套、购物袋等。为了满足用户的储物需求,并提供更加便捷的服务体验,当前设计了一款物联网智能储物柜。 该智能储物柜通…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...