You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理INT_MIN、LONG_MIN时void*转换问题及自定义printf故障排查

自定义printf的%p格式处理修复方案

我在实现自定义printf的%p格式处理函数时,要求使用write和while循环(禁止使用for和fputc)。当前代码在常规场景下可用,但处理INT_MIN、LONG_MIN、INT_MAX这类值时输出异常,无法匹配标准printf的结果。

原代码:

static int write_hex(unsigned char *buffer, int i)
{
    char    tmp;
    int     leading_zero;
    int     counter;

    leading_zero = 1;
    counter = 0;
    tmp = "0123456789abcdef"[buffer[i] / 16];
    if (tmp != '0' || !leading_zero)
    {
        write(1, &tmp, 1);
        leading_zero = 0;
        counter++;
    }
    tmp = "0123456789abcdef"[buffer[i] % 16];
    if (tmp != '0' || !leading_zero)
    {
        write(1, &tmp, 1);
        leading_zero = 0;
        counter++;
    }
    return (counter);
}

int handle_pointer(va_list args)
{
    int             i;
    int             counter;
    void            *ptr;
    unsigned char   *buffer;
    
    ptr = va_arg(args, void*);
    buffer = malloc(sizeof(ptr));
    ft_memcpy(buffer, &ptr, sizeof(ptr));
    i = 0;
    write(1, "0x", 2);
    counter = 2;
    while (buffer[i])
    {
        counter += write_hex(buffer, i);
        i++;
    }
    free(buffer);
    return (counter);
}

测试失败结果:

args:      [" %p %p ", INT_MIN, INT_MAX]
printf:    [ 0x80000000 0x7fffffff ] = 23
ft_printf: [ 0x 0xffffff7f ] = 15

问题分析

  1. 循环条件错误:原代码用while(buffer[i])判断是否继续遍历,会跳过所有值为0的字节。而指针的二进制表示中可能包含多个0字节(比如INT_MIN在小端系统中的内存有三个0字节),导致部分字节未被输出。
  2. 字节序颠倒:标准printf输出指针的十六进制值时,按高位到低位的顺序输出;而原代码直接按内存中的字节序(小端系统是低字节在前)输出,导致顺序完全颠倒。
  3. 前导零逻辑错误:write_hex函数对每个字节单独处理前导零,导致跨字节的前导零处理混乱,同时无法正确识别全局的前导零(比如指针值的高位全零但低位有值的情况)。

修复后的代码

static int write_hex_char(unsigned char c)
{
    char tmp;
    int counter = 0;
    // 输出高4位
    tmp = "0123456789abcdef"[c / 16];
    write(1, &tmp, 1);
    counter++;
    // 输出低4位
    tmp = "0123456789abcdef"[c % 16];
    write(1, &tmp, 1);
    counter++;
    return counter;
}

int handle_pointer(va_list args)
{
    int             i;
    int             counter;
    void            *ptr;
    unsigned char   *buffer;
    unsigned char   *start;
    size_t          ptr_size;

    ptr = va_arg(args, void*);
    ptr_size = sizeof(ptr);
    buffer = malloc(ptr_size);
    if (!buffer)
        return 0;
    ft_memcpy(buffer, &ptr, ptr_size);
    write(1, "0x", 2);
    counter = 2;

    // 找到第一个非零字节(从高位到低位)
    start = buffer + ptr_size - 1;
    while (start >= buffer && *start == 0)
        start--;

    // 如果全零(NULL指针),输出一个0
    if (start < buffer)
    {
        write(1, "0", 1);
        counter++;
    }
    else
    {
        // 从第一个非零字节开始,按高位到低位输出每个字节的十六进制
        i = start - buffer;
        while (i >= 0)
        {
            counter += write_hex_char(buffer[i]);
            i--;
        }
    }

    free(buffer);
    return counter;
}

修复说明

  1. 调整循环逻辑:先计算指针的字节长度ptr_size,遍历所有字节不再依赖字节值是否为0。
  2. 修正字节序:从指针内存的最高位字节开始遍历,找到第一个非零字节后,按高位到低位的顺序输出,匹配标准printf的输出顺序。
  3. 全局前导零处理:先跳过所有高位的零字节,只输出从第一个非零字节开始的内容;如果指针是NULL(全零),则输出0x0。
  4. 简化write_hex函数:改为write_hex_char,直接输出单个字节的两位十六进制,不再处理局部前导零,全局前导零统一在handle_pointer中处理。

内容的提问来源于stack exchange,提问作者Vinicius Bass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 23:08:10