当前位置: 首页 > news >正文

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_sprintf_num 函数

ngx_sprintf_num

声明就在 ngx_string.c 的开头

static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);

ngx_sprintf_num 实现

static u_char *
ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,ngx_uint_t hexadecimal, ngx_uint_t width)
{u_char         *p, temp[NGX_INT64_LEN + 1];/** we need temp[NGX_INT64_LEN] only,* but icc issues the warning*/size_t          len;uint32_t        ui32;static u_char   hex[] = "0123456789abcdef";static u_char   HEX[] = "0123456789ABCDEF";p = temp + NGX_INT64_LEN;if (hexadecimal == 0) {if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) {/** To divide 64-bit numbers and to find remainders* on the x86 platform gcc and icc call the libc functions* [u]divdi3() and [u]moddi3(), they call another function* in its turn.  On FreeBSD it is the qdivrem() function,* its source code is about 170 lines of the code.* The glibc counterpart is about 150 lines of the code.** For 32-bit numbers and some divisors gcc and icc use* a inlined multiplication and shifts.  For example,* unsigned "i32 / 10" is compiled to**     (i32 * 0xCCCCCCCD) >> 35*/ui32 = (uint32_t) ui64;do {*--p = (u_char) (ui32 % 10 + '0');} while (ui32 /= 10);} else {do {*--p = (u_char) (ui64 % 10 + '0');} while (ui64 /= 10);}} else if (hexadecimal == 1) {do {/* the "(uint32_t)" cast disables the BCC's warning */*--p = hex[(uint32_t) (ui64 & 0xf)];} while (ui64 >>= 4);} else { /* hexadecimal == 2 */do {/* the "(uint32_t)" cast disables the BCC's warning */*--p = HEX[(uint32_t) (ui64 & 0xf)];} while (ui64 >>= 4);}/* zero or space padding */len = (temp + NGX_INT64_LEN) - p;while (len++ < width && buf < last) {*buf++ = zero;}/* number safe copy */len = (temp + NGX_INT64_LEN) - p;if (buf + len > last) {len = last - buf;}return ngx_cpymem(buf, p, len);
}

作用:将给定的 64 位无符号整数格式化为字符串,并填充到目标缓冲区

buf:目标缓冲区

last:目标缓冲区的最后一个有效位置的下一个位置(防止溢出)

ui64:64 位无符号整数,要转换的数值

zero:用于填充的字符

hexadecimal 决定进制(0=十进制,1=小写十六进制,2=大写十六进制)

width 是输出字符串的总宽度(不足时填充)

返回指针指向最后一个有效字符的下一个位置,便于链式调用

u_char *p, temp[NGX_INT64_LEN + 1];  

temp 临时存放转换后字符的地方

p 指向这个临时区的当前处理位置

NGX_INT64_LEN 

NGX_INT64_LEN 的定义

在 ngx_config.h 中:

#define NGX_INT64_LEN   (sizeof("-9223372036854775808") - 1)

"-9223372036854775808":这是一个字符串,表示64位整数的最小值。64位整数的范围是从-9223372036854775808到9223372036854775807,这个字符串的长度就是64位整数转换成字符串后字符串的最大长度。

-1:因为字符串的长度包括了结尾的空字符\0,所以减去1,得到实际的数字长度。

为什么数组声明是 NGX_INT64_LEN + 1

注释说实际只需要 NGX_INT64_LEN,但为了消除 ICC 编译器的警告。可能的场景是:当从后向前填充 temp 数组时,严格检查数组越界的编译器可能误报,增加 +1 可以绕过这种警告。

size_t          len;

len:记录转换后的字符串的长度

uint32_t        ui32;

 如果 ui64 是 32 位以内的值则转为 uint32_t 处理,以减少 64 位除法的性能损耗

static u_char hex[] = "0123456789abcdef";  
static u_char HEX[] = "0123456789ABCDEF";  

为什么它们是静态(static)的?

因为这两个表在函数多次调用时内容不变。声明为 static 可以避免每次调用时重新初始化,节省时间和栈空间。

且十六进制转换需要频繁查表,静态表能提升性能。

p = temp + NGX_INT64_LEN;

初始化时,p 指向 temp 数组的末尾之后?这会不会越界?

这里 p 是一个指针,初始指向 temp 数组的“虚拟”末尾位置(temp[NGX_INT64_LEN])。当从后向前填充数字时,*--p 会先减指针再写入,因此第一个写入的位置是 temp[NGX_INT64_LEN - 1],确保不会越界。

if (hexadecimal == 0) {

hexadecimal == 0 表示采用十进制表示

if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) {ui32 = (uint32_t) ui64;

如果 ui64 是 32 位以内的值(<= NGX_MAX_UINT32_VALUE),则转为 uint32_t 处理,以减少 64 位除法的性能损耗

NGX_MAX_UINT32_VALUE

的定义在ngx_config.h 中:

#define NGX_MAX_UINT32_VALUE  (uint32_t) 0xffffffff

代表32位无符号整数的最大值


do {*--p = (u_char) (ui32 % 10 + '0');} while (ui32 /= 10);

通过循环取余 10,将每一位转为 ASCII 字符,从 temp 数组末尾向前填充

} else {do {*--p = (u_char) (ui64 % 10 + '0');} while (ui64 /= 10);}

大于32位无符号整数的最大值的情况

else if (hexadecimal == 1) {do {/* the "(uint32_t)" cast disables the BCC's warning */*--p = hex[(uint32_t) (ui64 & 0xf)];} while (ui64 >>= 4);

这段代码处理的是十六进制小写(hexadecimal == 1)的情况

do-while 循环,每次取 ui64 的最低 4 位(ui64 & 0xf),将其映射为十六进制字符(小写),然后右移 4 位,直到所有位处理完。结果从 temp 数组末尾向前填充。

每次循环后,右移 4 位相当于“丢弃”已处理的最低位,准备处理下一个 4 位组。例如,0xABC 第一次处理 C,右移后变为 0xAB,下一次处理 B,依此类推。

do-while 而非 while

即使 ui64 初始为 0,也会执行一次循环,输出 '0',确保数值 0 能被正确表示

else { /* hexadecimal == 2 */do {/* the "(uint32_t)" cast disables the BCC's warning */*--p = HEX[(uint32_t) (ui64 & 0xf)];} while (ui64 >>= 4);}

这部分处理的是十六进制大写的情况。

条件为hexadecimal == 2,对应大写十六进制。

类似于之前的十六进制小写处理,但使用的是HEX数组,包含大写字母。


len = (temp + NGX_INT64_LEN) - p;while (len++ < width && buf < last) {*buf++ = zero;}/* number safe copy */len = (temp + NGX_INT64_LEN) - p;if (buf + len > last) {len = last - buf;}return ngx_cpymem(buf, p, len);

这部分代码负责填充和复制处理后的数字到缓冲区。

首先,len = (temp + NGX_INT64_LEN) - p;

这里计算转换后的数字字符串的长度。

因为p指向有效字符的起始位置,而temp数组的起始地址加上NGX_INT64_LEN得到的是数组末尾,所以两者相减得到数字的实际长度。

接下来是填充循环:

while (len++ < width && buf < last)

这里len初始值是数字转换字符串后的长度,width是用户指定的总宽度。

如果数字长度小于width,就需要在数字前面填充zero字符(如'0'或空格),直到达到指定宽度。

每次循环填充一个字符,同时检查buf是否超过last,避免缓冲区溢出。

这里需要注意的是,len在循环条件中被自增,所以循环次数是width - len_initial,例如初始len为3,width为5,循环会执行两次,填充两个字符,使得总长度变为5。

接下来的 len = (temp + NGX_INT64_LEN) - p;

前面的填充循环修改了len变量,因此需要重新获取正确的数字长度

然后,检查if (buf + len > last),确定缓冲区剩余空间是否足够复制整个数字字符串

如果不够,则调整len为剩余空间的大小,防止溢出

最后使用ngx_cpymem函数将转换后的字符串从临时区复制到缓冲区,并返回新的buf位置。

相关文章:

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_sprintf_num 函数

ngx_sprintf_num 声明就在 ngx_string.c 的开头 static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width); ngx_sprintf_num 实现 static u_char * ngx_sprintf_num(u_char *buf, u_char *last,…...

Vue的状态管理:用响应式 API 做简单状态管理、状态管理库(Pinia )

文章目录 引言单向数据流多个组件共享一个共同的状态I 用响应式 API 做简单状态管理使用 reactive()创建一个在多个组件实例间共享的响应式对象使用ref()返回一个全局状态II 状态管理库Pinia枚举状态管理引言 单向数据流 每一个 Vue 组件实例都在“管理”它自己的响应式状态了…...

AI工具如何辅助写文章(科研版)

文章总览:[YuanDaiMa2048博客文章总览](https://blog.csdn.net/2301_79288416/article/details/137397359?spm=1001.2014.3001.5501)https://blog.csdn.net/2301_79288416/article/details/137397359?spm=1001.2014.3001.5501 在科研领域,撰写论文是一个复杂且耗时的过程。…...

LEED绿色建筑认证的重要意义

LEED&#xff08;Leadership in Energy and Environmental Design&#xff09;绿色建筑认证由美国绿色建筑委员会&#xff08;USGBC&#xff09;开发&#xff0c;是全球广泛认可的绿色建筑评估体系。其重要意义体现在以下几个方面&#xff1a; 1. 环境保护 资源节约&#xff1…...

阿里云 ubuntu22.04 中国区节点安装 Docker

下面是一份在 Ubuntu 22.04 (Jammy) 上&#xff0c;通过阿里云镜像源来安装并配置 Docker 的详细步骤示例&#xff0c;可在中国区阿里云节点使用&#xff1a; 一、卸载旧版本 (如已安装) 如果系统中已经安装了旧版 Docker (可能是 docker、docker-engine、docker.io、containe…...

【kafka的零拷贝原理】

kafka的零拷贝原理 一、零拷贝技术概述二、Kafka中的零拷贝原理三、零拷贝技术的优势四、零拷贝技术的实现细节五、注意事项一、零拷贝技术概述 零拷贝(Zero-Copy)是一种减少数据拷贝次数,提高数据传输效率的技术。 在传统的数据传输过程中,数据需要在用户态和内核态之间…...

Linux环境部署DeepSeek大模型

一、背景 【DeepSeek 深度求索】这个春节给了世界一个重磅炸弹&#xff0c;弄得美国都睡不好觉。这次与以往不同&#xff0c;之前我们都是跟随着美国的AI人工智能&#xff0c;现在DeepSeek通过算法上的优化&#xff0c;大大降低了训练模型所需的成本以及时间&#xff0c;短期造…...

React中key值的正确使用指南:为什么需要它以及如何选择

React中key值的正确使用指南&#xff1a;为什么需要它以及如何选择 一、key值的基本概念二、如何选择合适的key值1. 数据来源决定key策略2. key值的三大核心要求 三、React为何需要key值&#xff1f;1. 虚拟DOM优化机制2. 状态维护机制 四、常见误区及解决方案1. 索引作为key的…...

21.2.1 基本操作

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 Excel的基本操作步骤&#xff1a; 1、打开Excel&#xff1a;定义了一个Application对象&#xff1a; Microsoft.Office.Interop.E…...

车载以太网__传输层

车载以太网中&#xff0c;传输层和实际用的互联网相差无几。本篇文章对传输层中的IP进行介绍 目录 什么是IP&#xff1f; IP和MAC的关系 IP地址分类 私有IP NAT DHCP 为什么要防火墙穿透&#xff1f; 广播 本地广播 直接广播 本地广播VS直接广播 组播 …...

简单本地部署deepseek(软件版)

Download Ollama on Windows 下载 下载安装 winr 输入 cmd 然后输入ollama -v&#xff0c;出现ollama版本&#xff0c;安装成功 deepseek-r1 选择1.5b 输入 cmd 下面代码 ollama run deepseek-r1:1.5b 删除deepseek的代码如下&#xff1a; ollama rm deepseek-r1:1.5b 使用…...

AI绘画:解锁商业设计新宇宙(6/10)

1.AI 绘画&#xff1a;商业领域的潜力新星 近年来&#xff0c;AI 绘画技术以惊人的速度发展&#xff0c;从最初简单的图像生成&#xff0c;逐渐演变为能够创造出高度逼真、富有创意的艺术作品。随着深度学习算法的不断优化&#xff0c;AI 绘画工具如 Midjourney、Stable Diffu…...

20250202在Ubuntu22.04下使用Guvcview录像的时候降噪

20250202在Ubuntu22.04下使用Guvcview录像的时候降噪 2025/2/2 21:25 声卡&#xff1a;笔记本电脑的摄像头自带的【USB接口的】麦克风。没有外接3.5mm接口的耳机。 缘起&#xff1a;在安装Ubuntu18.04/20.04系统的笔记本电脑中直接使用Guvcview录像的时候底噪很大&#xff01; …...

cors跨域是如何做的?

CORS 跨域资源共享详解 什么是 CORS? CORS(Cross-Origin Resource Sharing)是一种机制,允许浏览器向不同源的服务器发出请求,从而实现跨域资源共享。默认情况下,浏览器出于安全考虑,禁止跨域请求。这意味着,当一个网页尝试从不同的域名、协议或端口加载资源时,浏览器…...

系统通解:超多视角理解

在科学研究和工程应用中&#xff0c;我们常常面临各种复杂系统&#xff0c;需要精确描述其行为和变化规律。从物理世界的运动现象&#xff0c;到化学反应的进程&#xff0c;再到材料在受力时的响应&#xff0c;这些系统的行为往往由一系列数学方程来刻画。通解&#xff0c;正是…...

最大矩阵的和

最大矩阵的和 真题目录: 点击去查看 E 卷 100分题型 题目描述 给定一个二维整数矩阵&#xff0c;要在这个矩阵中选出一个子矩阵&#xff0c;使得这个子矩阵内所有的数字和尽量大&#xff0c;我们把这个子矩阵称为和最大子矩阵&#xff0c;子矩阵的选取原则是原矩阵中一块相互…...

深度学习 | 表示学习 | 卷积神经网络 | Batch Normalization 在 CNN 中的示例 | 20

如是我闻&#xff1a; 让我们来用一个具体的例子说明 Batch Normalization 在 CNN 里的计算过程&#xff0c;特别是如何对每个通道&#xff08;channel&#xff09;进行归一化。 1. 假设我们有一个 CNN 层的输出 假设某个 CNN 层的输出是一个 4D 张量&#xff0c;形状为&#…...

最短木板长度

最短木板长度 真题目录: 点击去查看 E 卷 100分题型 题目描述 小明有 n 块木板&#xff0c;第 i ( 1 ≤ i ≤ n ) 块木板长度为 ai。 小明买了一块长度为 m 的木料&#xff0c;这块木料可以切割成任意块&#xff0c;拼接到已有的木板上&#xff0c;用来加长木板。 小明想让最…...

团体程序设计天梯赛-练习集——L1-034 点赞

前言 20分的题目题目不难&#xff0c;理解也不难&#xff0c;做起来有点问题 L1-034 点赞 微博上有个“点赞”功能&#xff0c;你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签&#xff0c;而你点赞的博文的类型&#xff0c;也间接刻画了你的特性。本…...

利用腾讯云cloud studio云端免费部署deepseek-R1

1. cloud studio 1.1 cloud studio介绍 Cloud Studio&#xff08;云端 IDE&#xff09;是基于浏览器的集成式开发环境&#xff0c;为开发者提供了一个稳定的云端工作站。支持CPU与GPU的访问。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器即可使用。Clo…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...