编程技能:格式化打印04,sprintf
专栏导航
本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏,故划分为两个专栏导航。读者可以自行选择前往哪个专栏。
(一)WIn32 专栏导航
上一篇:编程技能:格式化打印03,printf
回到目录
下一篇:无
(二)MFC 专栏导航
上一篇:编程技能:格式化打印03,printf
回到目录
下一篇:无
本节前言
在上一节,我们讲解了 printf 的实现代码。
本节,我们来讲解与之相近的 sprintf 的实现代码。
对于本节的讲解,是基于 vsprintf 的知识的。
如果你尚未学习过 vsprintf 的知识,请参考下述链接所示的文章。
编程技能:格式化打印02,vsprintf-CSDN博客
确保你理解了 vsprintf 的大致逻辑之后,接下来,我们来学习 printf 的实现代码。
在本节里面,我会用到三个术语。他们分别是【栈指针】,【格式字符串】和【参数列表】。这三个术语,均可以从 vsprintf 文章链接中找到。如果你不懂这些术语,请你先去上面的 vsprintf 文章链接中,学习好 vsprintf ,然后再进行本节的学习。
我们开始本节的讲解。
一. sprintf 函数的实现代码
代码如下。
extern int sprintf(char * str, const char *fmt, ...)
{va_list args;int i;va_start(args, fmt);i = vsprintf(str, fmt, args);va_end(args);return i;
}
这段代码,改编自 Linux 0.12 内核。绝大部分的代码,都与 0.12 内核一样。但是呢,我也的确是作出了一点小小的改动。
二. 调用 sprintf 函数的三个案例
下面是案例1 的代码。
static char buf01[300];
void func01(void)
{int i, a, c;float b;a = 90;b = 3.14;c = 1024;i = sprintf(buf01, "a = %d,b = %f,c = %x", a, b, c);return;
}
以上为案例1 的代码。
下面是案例2 的代码。
static char buf02[300];
void func02(void)
{int i;i = sprintf(buf02, "小雪的兜里有 %d 块钱", 100);return;
}
以上为案例 2 的代码。
下面是案例3 的代码
static char buf03[300];
void func03(void)
{int i;i = sprintf(buf03, "I have a pen");return;
}
以上为案例3 的代码。
这几个代码,我们在下面的讲解中,随时会引用。大家需要浏览一下这几个代码。一会儿,你需要随时来查阅对照这几个案例代码。
三. sprintf 的函数头部
sprintf 的函数头部如下。
extern int sprintf(char * str, const char *fmt, ...)
对于此函数的返回值,我们先不去讲。我们来看看它的各个参数。
(一)缓冲区
第一个参数,是字符指针 str 。这个字符指针,是由调用 sprintf 的函数提供的。
第二分节的案例1 代码里,包含有下述两行代码。
static char buf01[300];
i = sprintf(buf01, "a = %d,b = %f,c = %x", a, b, c);
在案例1 里面,我们声明了一个大的字符数组,里面包含 300 个元素。数组名为 buf01 。数组元素为 char 型,所以,数组名为字符指针。而在案例1 的调用 sprintf 函数的代码中,传入的第一个参数,为字符数组名 buf01 。
在案例2 和案例3 里面,也有类似的代码逻辑。也就是,申请了一个大的字符数组。同时,在调用 sprintf 函数的时候,给 sprintf 传入的第一个参数,是这个字符数组的数组名。
一般地,我们平时在申请数组的时候,不会让数组包含着这么多的元素个数。然而,在本节的第二分节的三个案例代码里面,我们的确是分别申请了一个大的字符数组。
申请这么大的数组干嘛?
一般来讲,当我们选择申请一个尺寸很大的数组的时候,我们是想要用它来临时地保存某些数据。这种临时地保存某些数据的,尺寸很大的数组,我们可以给它换一个名字,缓冲区。
在 Linux 0.12 内核里面,为了实现 printf 函数,它是申请了包含 1024 个 char 型元素的字符数组,作为缓冲区,来给 printf 函数使用。
关于缓冲区的概念,其实,大家在基础的 C 语言学习中,大家也听说过的。那就是键盘缓冲区。
在 Linux 0.12 内核里面,就包含有一个键盘缓冲区,它也是用包含着 1024 个元素的大数组,来作为键盘缓冲区的。
buf,常常用作【缓冲区】的含义,它是 buffer 的简写。
我们接着往下讲。
(二)格式字符串
在 sprintf 的函数头部里面,第二个参数,为【const char *fmt】。从这里可以看出,本参数用来接收一个字符串,并且,由于 const 关键字的存在,我们不可以通过字符指针 fmt 对这个接收的字符串进行任何改动,而只是可以使用其值。
在这里,我将 fmt 接收的字符串,称作格式字符串。
所谓的格式字符串,是说,它里面,可能会含有 %d,%c,%f,%s 等等的格式控制符。
在代码【printf("a = %d,b = %f,c = %x", a, b, c);】中,【"a = %d,b = %f,c = %x"】是格式字符串。类似地,在本文的的第二分节的案例1 代码里面,在代码【i = sprintf(buf01, "a = %d,b = %f,c = %x", a, b, c);】中, 【"a = %d,b = %f,c = %x"】也是格式字符串,由sprintf 的第二个形参 fmt 来接收。
在代码【printf("小雪的兜里有 %d 块钱", 100);】里面,【"小雪的兜里有 %d 块钱"】是格式字符串。类似地,在本文的的第二分节的案例2 代码里面,在代码【i = sprintf(buf02, "小雪的兜里有 %d 块钱", 100);】中, 【"小雪的兜里有 %d 块钱"】也是格式字符串,由sprintf 的第二个形参 fmt 来接收。
在代码【printf("I have a pen");】里面,【"I have a pen"】是格式字符串。类似地,在本文的的第二分节的案例3 代码里面,在代码【i = sprintf(buf03, "I have a pen");】中, 【"I have a pen"】也是格式字符串,由sprintf 的第二个形参 fmt 来接收。
格式字符串,里面可以包含有 %d 等等的格式控制符,也可以不包含。
到了这里,sprintf 的第二个形参我们就讲完了。我们接着讲。
(三)可变参数
在 sprintf 函数头部里面,在 fmt 形参的右边,是【...】,这个东西,不是省略号。你也可以在你自己的代码里面包含这样的东西。不过呢,使用的时候,是三个英文句点,不可以是中文的三个句点。在数量上,必须是三个,多一个不行,少一个也不行。
这个【...】,有一个专有名字,叫做可变参数。
可变参数,是说,它的数目是可变的,每一个参数的数据类型也是可变的,没有固定的范式。在数目方面,可变参数中,可以包含有一个参数,两个参数,或者多个参数,也可以不包含参数。
在代码【printf("a = %d,b = %f,c = %x", a, b, c);】中,【a, b, c】的部分,便是可变参数部分。类似地,在本文的的第二分节的案例1 代码里面,在代码【i = sprintf(buf01, "a = %d,b = %f,c = %x", a, b, c);】中,【a, b, c】的部分,也是可变参数部分。在此代码示例中,可变参数部分含有三个参数。
在代码【printf("小雪的兜里有 %d 块钱", 100);】中,【100】的部分,为可变参数部分。类似地,在本文的的第二分节的案例2 代码里面,在代码【i = sprintf(buf02, "小雪的兜里有 %d 块钱", 100);】中,【100】的部分,也是可变参数部分。在此代码示例中,可变参数部分含有一个参数。
在代码【printf("I have a pen");】里面,可变参数部分无参数。类似地,在本文的的第二分节的案例3 代码里面,在代码【i = sprintf(buf03, "I have a pen");】中,可变参数部分也是没有参数的。
在大家平时写代码的时候,应该不太会去使用可变参数的。不过,这次,我们要来学习 printf,vsprintf,sprintf 等等的打印函数,那就需要来接触可变参数了。
我尽力去讲,希望大家能够学好可变参数。
到了这里,sprintf 的函数头部,我们就先进行到这里。返回值,后面会有讲解。
四. va_list
我们来看下图的红色框线部分的代码。

图1 中的红色框线部分,是变量声明。【int i;】,这个简单,声明了一个整型变量 i 。问题在于【va_list args;】这一部分,需要去讲解一下的,是 va_list 。va_list,是【char *】的意思。
请看下面的参考代码。
typedef char *va_list;
va_list,是【char *】的别名。这样一来,由 va_list 声明的 args 变量,便是一个【char *】类型的变量。
在这里,我来讲一讲 va_list 的含义。va_list 中的 va,是【variable argument】的意思,翻译过来,就是可变参数的意思。list,是列表的含义。所以呢,va_list,整个的意思就是【可变参数列表】。用【可变参数列表】类型 va_list 声明的变量为 args,它是 arguments 的简写,就是【各个参数】的意思。
我们接着往下看。
五. va_start
我们来看下图中的红色框线部分的代码。

va_start,直接翻译,就是【可变参数开始】的意思。其实,它是用来对可变参数变量 args 进行初始化的宏函数。
va_start,从它的使用方法上看,似乎是一个函数。实际上,它是一个宏。对于这种,实际上为宏,而外形为函数的东西,我将其称作宏函数。别的地方咋叫我记不清了。反正我就管它叫宏函数。
va_start,它的宏代码,具体是什么,在这里,我不展开。原因在于,想要彻底理解其宏代码,你需要具备汇编语言基础。在设计本专栏教程的时候,我的一个基本的假定,就是,各位读者并不具备汇编语言基础。我希望在各位并不具备汇编语言基础的情况下,也能够看懂本专栏教程。
由于假定各位不懂汇编语言,所以,va_start 的宏代码,我就不去细讲了。但是呢,它的功能,我还得来说一说的。
va_start(args, fmt) 的意思是说,将可变参数变量 args,赋值为 fmt 右边的可变参数列表中第一个变量的栈指针。
栈指针又是什么?
我们在讲解 vsprintf 的时候,有去详细讲它。
在讲解 vsprintf 的时候,我们所给出的栈指针的大致含义如下。
A 函数调用 B 函数的时候,会将 B 函数所需要的参数,也就是传递给 B 函数的实参,压入栈中。完成了参数入栈的工作以后,CPU 才会前往执行 B 函数的代码。那么,A 函数所传递的某一个参数在栈中的位置,就是这个实参的栈指针。
在这里,如果你需要进一步理解栈指针的含义,那么,你可以参考 vsprintf 的讲解。讲解 vsprintf 的文章链接如下所示。
编程技能:格式化打印02,vsprintf-CSDN博客
不过,说实话,我在讲解 vsprintf 的时候,对栈指针的讲解,做不到让你彻底地理解栈指针的含义。因为,想要彻底地理解栈指针的概念,你需要具备汇编语言基础。此处,你只要能够模糊地,大致地理解栈指针的概念就可以了。
我们接着往下讲。
为了辅助大家理解 va_start 的含义,我们来举几个例子。
在案例1 中的代码【i = sprintf(buf01, "a = %d,b = %f,c = %x", a, b, c);】中,在调用了 sprintf 函数以后,在 sprintf 函数内部,代码【va_start(args, fmt);】的执行,会将 args 赋值为格式字符串【"a = %d,b = %f,c = %x"】右边的可变参数列表中的第一个参数,a 的栈指针。
在案例2 中的代码【i = sprintf(buf02, "小雪的兜里有 %d 块钱", 100);】里面,在调用了 sprintf 函数以后,在 sprintf 函数内部,代码【va_start(args, fmt);】的执行,会将 args 赋值为格式字符串【"小雪的兜里有 %d 块钱"】右边的可变参数列表中的第一个参数,【100】的栈指针。
在案例3 中的代码【i = sprintf(buf03, "I have a pen");】里面,可变参数部分无参数。在这种情况下,代码【va_start(args, fmt);】的执行也会令 args 指向一个东西,不过,在可变参数部分无参数的情况下,args 究竟是指向啥,我们就不必关心了。我们暂时只关心可变参数列表中至少含有一个参数的情形,并且将可变参数列表中包含至少一个参数的情形视为典型。
再次重复一下,va_start(args, fmt) 的意思是说,将可变参数变量 args,赋值为 fmt 所指向的格式字符串右边的可变参数列表中的第一个变量的栈指针。
正是在 va_start 宏函数的作用之下,可变参数列表中的第一个参数的栈指针,被提取出来了。
不知道,你理解得是否费劲儿。反正,此刻,我是觉得,讲得挺费劲儿的。
接着来吧。
六. 调用 vsprintf
我们接着看下图的红色框线所示的代码。

在图3 的红色框线部分,我们调用了 vsprintf 函数,传给它的三个参数,分别是由上一级的调用函数传过来的字符缓冲区指针【str】,格式字符串的指针【fmt】,还有可变参数列表中第一个参数的栈指针【args】。
vsprintf 函数的功能,是根据 fmt 与 args,对 fmt 所指向的格式字符串进行格式化转换,转换结果放在字符缓冲区指针 str 所指向的字符数组里面。格式化转换的工作完成以后,str 中的字符串的不含 NUL 结束符的有效字符长度,会作为返回值,予以返回。在图3 里面,这个返回值由 int 型变量 i 来接收了。
vsprintf 是如何进行格式化转换的,请大家参考 vsprintf 文章链接,链接如下。
编程技能:格式化打印02,vsprintf-CSDN博客
不过呢,在这里,虽说我不想细讲 vsprintf 的执行过程。不过呢,我还是想要举几个例子。
例如,在执行本文第二分节的案例1 中的代码【i = sprintf(buf01, "a = %d,b = %f,c = %x", a, b, c);】以后,sprintf 会在内部调用 vsprintf 。 vsprintf 会根据格式字符串【"a = %d,b = %f,c = %x"】与可变参数列表中第一个参数的栈指针,对格式字符串进行格式化转换。对于案例1 而言,格式化转换的结果为【"a = 90,b = 3.14,c = 400"】,这个转换结果会被存放在 str 缓冲区里面,或者说是存放在案例1 中的 buf01 缓冲区里面。十进制 1024 的十六进制值为 0x400 。我在格式字符串里面,没有给十六进制值加上十六进制前缀,你可以自己添加啊。这里,我偷个懒。
再比如,在执行本文第二分节的案例2 中的代码【i = sprintf(buf02, "小雪的兜里有 %d 块钱", 100);】以后,sprintf 会在内部调用 vsprintf 。 vsprintf 会根据格式字符串【"小雪的兜里有 %d 块钱"】与可变参数列表中第一个参数的栈指针,对格式字符串进行格式化转换。格式化转换的结果为【"小雪的兜里有 100 块钱"】,这个转换结果会被存放在 str 缓冲区里面,或者说是存放在案例2 中的 buf02 缓冲区里面。
再比如,在执行本文第二分节的案例3 中的代码【i = sprintf(buf03, "I have a pen");】以后,sprintf 会在内部调用 vsprintf 。 vsprintf 会根据格式字符串【"I have a pen"】与可变参数列表中第一个参数的栈指针,对格式字符串进行格式化转换。在此例子代码中,由于格式字符串里面不含有格式控制符,可变参数列表里面也不含有参数,因此,vsprintf 的工作,是直接把字符串【"I have a pen"】放在 str 缓冲区中,或者说是存放在案例3 中的 buf03 缓冲区中,而并不需要专门的格式化转换工作。
我们接着往下看。
七. va_end
我们来看下图的红色框线部分所示的代码。

va_end,依然是一个宏函数。
va_end(args),它的作用,是将 args 置空。由于 args 是 va_list 类型的,也就是【char *】类型,所以呢,【va_end(args);】的作用,相当于执行代码【args = NULL;】。就这么简单。在这里,我将 va_end 的宏代码给展示一下。
#define va_end(AP) (AP = NULL)
这个宏代码,应该是不难吧?
如果不理解的话,请查阅 C 语言基础知识教材。
在 va_start 宏函数里面,初始化了 args 变量。在调用 vsprintf 的时候,使用了 args 变量。最后呢,在 va_end 宏函数里面,清理了 args 变量。
我们接着往下看。
八. 打印输出与返回
请先看下图的红色框线所示的代码。

图5 中的红色框线部分,是返回语句【return i】。
关于变量 i,在本文的第六节中,讲解 vsprintf 函数调用的时候,我谈到了,vsprintf 会将完成了格式化转换工作以后,保存在 str 缓冲区中的字符串的不含有 NUL 结束符的有效字符长度作为返回值,予以返回。这个返回值,被赋值给 int 型变量 i 了。
所以呢,此时,变量 i 里面所保存的,是 str 缓冲区中的字符串的不含有 NUL结束符的有效字符长度。
而在 sprintf 函数实现代码的末尾,这个有效字符长度,再一次作为返回值,予以返回了。
在我的学习经历中,这个返回值,还是有用的。至于究竟是如何来使用,我们在以后的 Windows 编程教程中,会见到的。
WIndows 编程,我打算分为 Win32 与 MFC 两块来讲。在 MFC 专栏里面,可能对 sprintf 用得不多。然而,在 Win32 专栏里面,我们用 sprintf 会多一些。当然了,我们不是直接用 sprintf ,而是用它的 WIndows 版本,wsprintf 函数。
九. sprintf 函数总结
我们对 sprintf 的函数功能进行一个小小的总结。
我们还是先来看一下 sprintf 的函数头部。
extern int sprintf(char * str, const char *fmt, ...);
sprintf 函数的功能,根据 fmt 所指向的格式字符串与可变参数列表中第一个参数的栈指针,对格式字符串进行格式化转换工作。转换好的字符串,会被存放在 str 缓冲区里面。函数的返回值,为格式化转换工作完成以后,存放在 str 缓冲区中的字符串的不含有 NUL 结束符的有效字符长度。
对函数返回值部分,我特意用橄榄色的粗体字来标识了。我还是再来重复一下。简单地来讲,sprintf 函数的返回值,为有效字符长度。
到了这里,本节的讲课任务就都完成了。
结束语
相比上一节讲解 printf 的时候来讲,本节的写作,算是轻松了一些,因为大部分都是复制粘贴。然而,也还有许多东西是需要去修改的。
sprintf,我认为是比较重要的函数。希望大家能够学习好它。
其实,到了这里,主体任务,vsprintf,printf,sprintf,这三大格式化打印函数,我们就都讲完了。到了这里,格式化打印部分,可以说是完成了。
不过,我还想要补充一点东西。那就是,对于格式控制符,它还有一些个东西,我想要去补充补充。也许,这个补充是不必要的。不过,我还是想要补充一下。
下一节,将会是格式化打印板块的最后一节。同时,Windows 编程的预备知识部分,也将在下一节画上句号。
本节结束。
专栏导航
本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏,故划分为两个专栏导航。读者可以自行选择前往哪个专栏。
(一)WIn32 专栏导航
上一篇:编程技能:格式化打印03,printf
回到目录
下一篇:无
(二)MFC 专栏导航
上一篇:编程技能:格式化打印03,printf
回到目录
下一篇:无
相关文章:

编程技能:格式化打印04,sprintf
专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏,故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 (一)WIn32 专栏导航 上一篇:编程技能:格式化打印03,printf 回到目录…...
C语言基础(11)【函数1】
内容提要 函数 文章目录 内容提要函数函数的描述函数的分类相关概念函数的定义:定义:案例: 形参和实参形参(形式参数)实参(实际参数)案例: 函数的返回值案例: 函数 函数…...

R语言基础| 下载、安装
在此前的单细胞教程中,许多小伙伴都曾因为R语言基础不足而十分苦恼。R语言是一种开源的编程语言和软件环境,专门用于统计分析、图形表示和数据挖掘。它最初由Ross Ihaka和Robert Gentleman在1993年创建,旨在为统计学家和数据分析师提供一个广…...
【hive sql】窗口函数
参考 包括窗口函数在内的执行顺序 from & join --确定数据源 where --行级过滤 group by --分组 having --组级过滤 窗口函数 --计算窗口函数结果 select --选择列 distinct --去重 order by --最终排序(可对窗口函数结果进行排序) limit/offset -…...
Ubuntu24.04 交叉编译 aarch64 ffmpeg
ffmpeg 官网: https://ffmpeg.org文档: https://ffmpeg.org/documentation.html 编译参数说明: https://trac.ffmpeg.org/wiki/CompilationGuide/Generic在Linux下编译: https://trac.ffmpeg.org/wiki/CompilationGuide 下载页: https://ffmpeg.org/download.html 安装依赖 …...
《AI角色扮演反诈技术解析:原理、架构与核心挑战》
AI角色扮演反诈技术解析:原理、架构与核心挑战 研究目标 技术栈梳理: 系统总结AI角色扮演在执法场景中的实现路径,涵盖大型语言模型(LLM)、提示词工程(Prompt Engineering)、多模态交互链路等…...

微软的新系统Windows12未来有哪些新特性
在今年即将到来的重大设计升级中,苹果计划对其全线操作系统统一按年份命名,作为另一巨头微软的win12还远吗?win11和win10是微软现在正在用的主流版本,win11系统发布于2021年6月24日,win10系统发布于2015年7月29日。预计win12尝鲜版可能在2025年下半年或明年。 尽管win12还…...
树莓派超全系列教程文档--(54)如何使用rsync在计算机之间同步文件夹
如何使用rsync在计算机之间同步文件夹 使用 rsync 在计算机之间同步文件夹 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rsync 在计算机之间同步文件夹 您可以使用 rsync 在计算机之间同步文件夹。例如,您可以使用 rsync 将R…...
华为ICT和AI智能应用
在华为的业务布局中,AI智能创新则贯穿于华为多个业务领域,二者紧密相关,共同推动华为及相关行业的发展。以下是具体介绍: Techco转型 - 背景:随着5G - A、云、人工智能等技术的发展,运营商从传统连接服…...
ROS2与Unitree机器人集成指南
Tested systems and ROS2 distro systemsROS2 distroUbuntu 20.04foxyUbuntu 22.04humblesrc目录上级才可以colcon build git clone https://github.com/unitreerobotics/unitree_ros2 Install Unitree ROS2 package 1. Dependencies sudo apt install ros-humble-rmw-cyclon…...

在虚拟宇宙中低语——进程间通信,Linux命名管道的前世今生
文章目录 🌌 序章🌠 一、命名管道的宿命与哲学1.1、创建及简单使用1.2、命名管道的工作原理1.3、命名管道与匿名管道的区别 2、命名管道的特点及特殊场景2.1、特点2.2、四种特殊场景 3、命名管道实操3.1、实现文件拷贝3.2、实现进程控制 小结 dz…...
Cursor 工具项目构建指南:Java 21 环境下的 Spring Boot Prompt Rules 约束
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 Cursor 工具项目构建指南:Java 21 环境下的 Spring Boot Prompt Rules 约束前言项目简…...
各个布局的区别以及示例
各个布局的区别以及示例 在前端开发中,常见的布局方式主要有以下几种,每种布局都有其适用场景和特点: 1. 普通文档流(Normal Flow) 特点:默认布局方式,元素按照HTML顺序依次排列。适用场景&am…...
什么是MVC?
导语: 在Java后端面试中,“MVC架构”是绕不开的基础话题。它不仅关乎项目的整体设计思路,更体现了候选人的架构理解能力与编码规范意识。本文将从面试官视角出发,结合高频问题、代码示例、答题技巧与加分项,带你全面吃…...

STM32的ADC简介
一、ADC简介 STM32的ADC是一种12位逐次逼近型模拟数字转换器。它具备18个通道,能够测量16个外部信号源以及2个内部信号源。各通道的A/D转换可以执行单次、连续、扫描或间断模式。转换结果可采用左对齐或右对齐的方式(12位)存储于16位数据寄存…...

Bash shell四则运算
文章目录 四则运算1. expr 命令2. $(( )) 表达式(推荐)3. $[ ] 表达式(已弃用)4. let 命令小数运算i 和 i 区别 四则运算 算术运算: - * / %(取模,求余数) Bash sh…...

(javaSE)Java数组进阶:数组初始化 数组访问 数组中的jvm 空指针异常
数组的基础 什么是数组呢? 数组指的是一种容器,可以用来存储同种数据类型的多个值 数组的初始化 初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。 数组初始化的两种方式:静态初始化,动态初始化 数组的静态初始化 初始化…...

力扣刷题Day 70:在排序数组中查找元素的第一个和最后一个位置(34)
1.题目描述 2.思路 方法1(自己写的):一次二分查找找到等于target的一个元素索引axis,然后向左右延伸找边界。 方法2(灵茶山艾府佬的闭区间二分查找写法):定义一个lower_bound()函数找到第一个…...
vue 多端适配之pxtorem
在 Vue 3 Vite 项目中使用 postcss-pxtorem 自动将 px 单位转换为 rem 单位,可以按照以下步骤配置: 一、基础版本 1. 安装依赖 首先安装必要的插件: npm install postcss postcss-pxtorem autoprefixer -D # 或 yarn add postcss postcs…...

图片压缩工具 | 图片属性详解及读取解析元数据
ℹ️ 图片信息及属性 基本属性 格式类型:JPEG、PNG、GIF、WEBP、BMP、TIFF等文件大小:以KB、MB等为单位的存储空间占用创建/修改日期:文件的元数据时间戳 视觉属性 尺寸/分辨率 宽度(像素)高度(像素&…...
React---day8
9.6 不可变数据的力量 我们知道是不能够修改this.state里面的数据的 举个例子 export class App extends React.PureComponent{constructor(){super();this.state {userList:[{name : "tom" , age : 18},{name : "lily" , age : 20},{name : "tik…...

C# Onnx 动漫人物人脸检测
目录 效果 模型信息 项目 代码 下载 参考 效果 模型信息 Model Properties ------------------------- stride:32 names:{0: face} --------------------------------------------------------------- Inputs ------------------------- name&am…...

C++内存列传之RAII宇宙:智能指针
文章目录 1.为什么需要智能指针?2.智能指针原理2.1 RAll2.2 像指针一样使用 3.C11的智能指针3.1 auto_ptr3.2 unique_ptr3.3 shared_ptr3.4 weak_ptr 4.删除器希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力! 智能指针是 C 中用于自动…...

PVE 虚拟机安装 Ubuntu Server V24 系统 —— 一步一步安装配置基于 Ubuntu Server 的 NodeJS 服务器详细实录1
前言 最近在基于 NodeJS V22 写一个全栈的项目,写好了,当然需要配置服务器部署啦。这个过程对于熟手来说,还是不复杂的,但是对于很多新手来说,可能稍微有点困难。所以,我把整个过程全部记录一下。 熟悉我…...
GitHub 趋势日报 (2025年06月03日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 2404 onlook 860 system-design-primer 380 nautilus_trader 372 agent-zero 357 …...
出现dev/nvmeOnip2 contains a file system with errors, check forced 解决方法
目录 前言1. 问题所示2. 原理分析3. 解决方法4. 彩蛋前言 爬虫神器,无代码爬取,就来:bright.cn Java基本知识: java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)【Java项目】实战CRUD的功能整理(持续更新)1. 问题所示 出现如下问题: dev/nvmeOnip2 co…...
Vue3.5 企业级管理系统实战(二十二):动态菜单
在前几篇内容中已完成菜单、角色及菜单权限等相关开发,若要在左侧菜单根据用户角色动态展示菜单,需对 Sidebar 中的相关数据进行修改。鉴于其他相关方法及类型已在前文实现,本文不再重复阐述。 1 修改 Sidebar 组件 在 src/layout/componen…...
磨皮功能 C++/C的OpenCV 实现
磨皮功能 C/C的OpenCV 实现 前提条件 OpenCV 安装: 你需要正确安装 OpenCV 库。C 编译器: 如 G。 C 代码 #include <opencv2/opencv.hpp> #include <iostream> #include <string>// 使用标准命名空间 using namespace std; using …...
蓝牙防丢器应用方案
蓝牙防丢器通常由两个主要部分构成:一个小型装置,亦称为标签,以及一个与之配对的手机应用程序。该标签内置一个微型蓝牙芯片,能够与配对的手机应用程序进行通信。一旦标签与手机之间的连接中断,手机应用程序便会接收到…...

TDengine 开发指南——高效写入
高效写入 本章内容将介绍如何发挥 TDengine 最大写入性能,通过原理解析到参数如何配置再到实际示例演示,完整描述如何达到高效写入。 为帮助用户轻松构建百万级吞吐量的数据写入管道,TDengine 连接器提供高效写入的特性。 启动高效写入特性…...