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

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

ngx_sprintf_str 函数

ngx_sprintf_str 声明在 ngx_string.c 的开头

static u_char *ngx_sprintf_str(u_char *buf, u_char *last, u_char *src,
    size_t len, ngx_uint_t hexadecimal);

ngx_sprintf_str 实现在ngx_string.c中

static u_char *
ngx_sprintf_str(u_char *buf, u_char *last, u_char *src, size_t len,
    ngx_uint_t hexadecimal)
{
    static u_char   hex[] = "0123456789abcdef";
    static u_char   HEX[] = "0123456789ABCDEF";

    if (hexadecimal == 0) {

        if (len == (size_t) -1) {
            while (*src && buf < last) {
                *buf++ = *src++;
            }

        } else {
            len = ngx_min((size_t) (last - buf), len);
            buf = ngx_cpymem(buf, src, len);
        }

    } else if (hexadecimal == 1) {

        if (len == (size_t) -1) {

            while (*src && buf < last - 1) {
                *buf++ = hex[*src >> 4];
                *buf++ = hex[*src++ & 0xf];
            }

        } else {

            while (len-- && buf < last - 1) {
                *buf++ = hex[*src >> 4];
                *buf++ = hex[*src++ & 0xf];
            }
        }

    } else { /* hexadecimal == 2 */

        if (len == (size_t) -1) {

            while (*src && buf < last - 1) {
                *buf++ = HEX[*src >> 4];
                *buf++ = HEX[*src++ & 0xf];
            }

        } else {

            while (len-- && buf < last - 1) {
                *buf++ = HEX[*src >> 4];
                *buf++ = HEX[*src++ & 0xf];
            }
        }
    }

    return buf;
}

ngx_sprintf_str函数,它负责将数据按不同格式写入缓冲区

u_char *buf:目标缓冲区的起始位置,用来写入结果。

u_char *last:缓冲区的末尾指针(指向最后一个有效位置的下一个位置),防止越界。

u_char *src:源数据(比如要处理的字符串或二进制数据)。

size_t len:要处理的源数据长度。如果传(size_t)-1(即-1的无符号形态)(未指定长度),表示src是字符串,直到遇到\0结束。

ngx_uint_t hexadecimal:控制输出格式:0是普通字符串,1是小写十六进制,2是大写十六进制。

返回值指向最后一个有效位置的下一个位置,也是下一个可写入位置,方便用于进行链式操作


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

这两个数组是十六进制转换的核心工具

就像密码本一样,把4位二进制数(0-15)翻译成对应的字符

hex[] 是小写字母版(a-f)

HEX[] 是大写字母版(A-F)

假设我们要转换字节0xAE(二进制10101110):

// 拆分高4位和低4位

高4位 = 0xA(1010) → hex[0xA] → 'a'

低4位 = 0xE(1110) → hex[0xE] → 'e'

// 组合成"ae"


    if (hexadecimal == 0) {

        if (len == (size_t) -1) {
            while (*src && buf < last) {
                *buf++ = *src++;
            }

        } else {
            len = ngx_min((size_t) (last - buf), len);
            buf = ngx_cpymem(buf, src, len);
        }

当hexadecimal为0时,处理的是非十六进制情况,直接复制原始字节

2种情况:

if (len == (size_t) -1)

表示未指定长度

while (*src && buf < last)

未指定长度的情况下循环的两个终止条件:

1:*src 遇到 \0 (字符串结束标志)

2: buf 触达缓冲区末尾 last,防止溢出

*buf++ = *src++
逐字节复制字符,同时移动目标指针 buf 和源指针 src,继续进行下一个字符的处理

else 就是指定了长度的情况

len = ngx_min((size_t)(last - buf), len)

计算安全的复制长度,取「剩余缓冲区空间」和「用户指定长度」的较小值,防止溢出

ngx_min 的定义在 ngx_core.h:

#define ngx_min(val1, val2)  ((val1 > val2) ? (val2) : (val1))

buf = ngx_cpymem(buf, src, len)

内存复制函数(类似 memcpy),但返回值是目标地址末尾位置,直接更新 buf(指向最后一个有效位置的下一个位置


    } else if (hexadecimal == 1) {

        if (len == (size_t) -1) {

            while (*src && buf < last - 1) {
                *buf++ = hex[*src >> 4];
                *buf++ = hex[*src++ & 0xf];
            }

        } else {

            while (len-- && buf < last - 1) {
                *buf++ = hex[*src >> 4];
                *buf++ = hex[*src++ & 0xf];
            }
        }

else if (hexadecimal == 1)

进入小写十六进制模式,将每个字节拆解为两个十六进制字符(如 0xAB → 'a''b'

if (len == (size_t)-1)

表示未指定长度的情况下

while (*src && buf < last - 1)

终止条件 1:*src 遇到 \0

终止条件 2:缓冲区至少保留 2 字节空间

*buf++ = hex[*src >> 4]

取字节高 4 位(如 0xA0 → 0xA),查表 hex 得到字符('a'),存入buf 指向的位置,buf 加 1,指向下一个可写入位置

*buf++ = hex[*src++ & 0xf]
取低 4 位(如 0xA5 → 0x5),查表得到字符('5'),存入buf 指向的位置,buf 加 1,指向下一个可写入位置,同时移动 src 指针,指向下一个要处理的字符

else 

指定长度的情况下

while (len-- && buf < last - 1)
通过 len-- 控制循环次数,确保不超出指定长度

buf < last - 1 缓冲区至少保留 2 字节空间

之后操作同上


    } else { /* hexadecimal == 2 */

        if (len == (size_t) -1) {

            while (*src && buf < last - 1) {
                *buf++ = HEX[*src >> 4];
                *buf++ = HEX[*src++ & 0xf];
            }

        } else {

            while (len-- && buf < last - 1) {
                *buf++ = HEX[*src >> 4];
                *buf++ = HEX[*src++ & 0xf];
            }
        }
    }

处理 hexadecimal == 2 的情况,也就是将字节转成 大写十六进制字符串

逻辑同上


http://www.kler.cn/a/533827.html

相关文章:

  • RocketMQ实战—4.消息零丢失的方案
  • 【数据分析】豆瓣电影Top250的数据分析与Web网页可视化(numpy+pandas+matplotlib+flask)
  • 每日一题洛谷P5721 【深基4.例6】数字直角三角形c++
  • DeepSeek 使用及本地安装教程
  • 【缴纳过路费——并查集】
  • 蓝桥杯例题七
  • 蓝桥杯思维训练(五)
  • 【Day31 LeetCode】动态规划DP Ⅳ
  • 在深度学习中,样本不均衡问题是一个常见的挑战,尤其是在你的老虎机任务中,某些的中奖倍数较高
  • 网络安全-设备安全加固
  • 【前端】【Ts】【知识点总结】TypeScript知识总结
  • 使用DeepSeek R1 + 了解部署
  • 从离散傅里叶变换(DFT)到快速傅里叶变换(FFT)
  • 【蓝桥杯嵌入式】工程创建
  • MapStruct工具类的使用
  • [论文笔记] Deepseek技术报告
  • 【Elasticsearch】`auto_date_histogram`聚合功能详解
  • MLA 架构
  • Ubuntu部署Deepseek-R1模型(8b)
  • 基于微信小程序的医院综合服务平台的设计与实现ssm+论文源码调试
  • 亚博microros小车-原生ubuntu支持系列:22 物体识别追踪
  • AI绘画:解锁商业设计新宇宙(6/10)
  • 使用request库实现接口测试-笔记
  • 阿里云 ubuntu22.04 中国区节点安装 Docker
  • 2024年12月 Scratch 图形化(一级)真题解析 中国电子学会全国青少年软件编程等级考试
  • arm 下 多线程访问同一变量 ,使用原子操作 性能差问题