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

如何通过printf格式字符串用单个说明符打印可变数量字节?

答案

结论

标准C库的printf没有原生支持该需求的单个格式说明符,但结合你使用的Ubuntu 20.04自带的GNU libc环境,可以通过两种方案实现预期效果。

方案1:使用GNU libc自定义格式说明符(实现你提到的%kmagic效果)

GNU libc提供了register_printf_function接口,允许你自定义格式说明符的处理逻辑:

  1. 注册自定义说明符比如%M,约定前缀的数字参数为要读取的字节数k
  2. 处理函数中直接从可变参数栈读取k个连续字节,逐字节转换为两位十六进制字符输出即可
    示例代码片段:
#include <printf.h>
#include <stdint.h>

static int print_bytes(FILE *stream, const struct printf_info *info, const void *const *args) {
    int k = info->width; // 取格式说明符前缀的数字作为字节数
    const uint8_t *buf = *(const uint8_t **) args[0]; // 取栈指针参数
    for (int i = 0; i < k; i++) {
        fprintf(stream, "%02hhx", buf[i]);
    }
    return k * 2;
}

static int print_bytes_arginfo(const struct printf_info *info, size_t n, int *argtypes, int *size) {
    if (n > 0) argtypes[0] = PA_POINTER;
    return 1;
}

// 注册后就可以用%<k>M格式说明符,参数传栈地址即可输出k字节十六进制
int main() {
    register_printf_function('M', print_bytes, print_bytes_arginfo);
    uint32_t test = 0xefbeadde; // 小端存储对应0xde 0xad 0xbe 0xef
    printf("Next 4 bytes on the stack: %4M\n", &test);
    // 输出:Next 4 bytes on the stack: deadbeef
    return 0;
}

方案2:无自定义扩展的替代方案

如果不想修改libc的printf行为,可直接重复使用%.2hhx说明符,每个说明符对应读取1字节:

  • 要输出4字节就写printf("Next 4 bytes on the stack: %.2hhx%.2hhx%.2hhx%.2hhx\n", *(uint8_t*)rsp, *(uint8_t*)(rsp+1), *(uint8_t*)(rsp+2), *(uint8_t*)(rsp+3));
  • 输出结果和预期完全一致,唯一缺点是需要对应写k个格式说明符,不是单个说明符。

为什么你之前的尝试不生效

你用到的%khhx、%kx中的k是宽度修饰符,作用是指定输出的最小总长度,不足时补空格,和读取多少字节无关:

  • %hhx固定只读取1个字节,输出2个十六进制字符,你写%4hhx就会输出2个字符加2个前置空格,总长度为4,和你观察到的现象一致
  • %x在x86-64环境下固定读取4字节unsigned int类型,输出最多8个十六进制字符,你写%10x就会输出8个字符加2个前置空格,总长度为10。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:36:03