使用带有 printf 的格式字符串打印可变字节数
Posted
技术标签:
【中文标题】使用带有 printf 的格式字符串打印可变字节数【英文标题】:Printing variable number of bytes using format strings with printf 【发布时间】:2022-01-05 02:41:36 【问题描述】:目标:使用单个格式说明符打印可变数量的字节。
环境: x86-64 Ubuntu 20.04.3 LTS 在 x86-64 主机上的 VM 中运行。
示例:
让%kmagic
成为我正在寻找的格式说明符,它通过从堆栈中弹出它们并将它们添加到输出中来打印k
字节。然后,对于指向内存中保存字节0xde 0xad 0xbe 0xef
的内存区域的%rsp
,我希望printf("Next 4 bytes on the stack: %4magic")
打印Next 4 bytes on the stack: deadbeef
。
到目前为止我尝试了什么:
%khhx
,不幸的是,这只会导致 k-1
空格后跟两个十六进制字符(一个字节的数据)。
%kx
,我希望将 k/2 字节打印为一个数字。这只会打印 8 个十六进制字符(4 个字节),前面有 k - 8 个空格。
打印的非空白字符数与格式说明符的长度匹配,即%hhx
的预期长度为 2,这也是打印的非空白字符数。 %x
也是如此,预计会打印 8 个字符。
问题: 是否有可能获得所需的行为?如果有,怎么做?
【问题讨论】:
"是否可以获得所需的行为?" --> 是的。 “如果是,怎么做?”你在找人为你写这段代码吗? “到目前为止我尝试了什么:” --> 发布该代码。 作为问题中的状态,我正在寻找一个格式说明符,而不是一个自定义的 printf 实现,它可以满足我的需求。所以不,我不是在找人为我编写代码,而是在找人告诉我说明符。当我正在寻找说明符而不是任何代码时,编写我尝试过的说明符就足够了。发布“代码”,例如printf("I want 4 bytes: %4hhx");
只是添加样板。
【参考方案1】:
是否有可能获得所需的行为?如果有,怎么做?
不存在 printf
格式说明符来做你想做的事。
可能
编写您自己的printf
实现来支持您想要的。使用 implementation-specific tools 创建您自己的 printf
格式说明符。您可以从linux kernel printk %*phN
format speciifer 获得灵感。
【讨论】:
【参考方案2】:无法使用标准printf
。需要自己编写函数,自定义printf
函数。
http://www.gnu.org/software/libc/manual/html_node/Customizing-Printf.html
示例(简单转储):
int printdump (FILE *stream, const struct printf_info *info, const void *const *args)
const unsigned char *ptr = *(const unsigned char **)args[0];
size_t size = *(size_t*)args[1];
for(size_t i = 1; i <= size; i++)
fprintf(stream, "%02X%c", ptr[i-1], i % 8 ? ' ' : '\n');
return 1;
int printdumpargs (const struct printf_info *info, size_t n, int *argtypes)
if (n == 2)
argtypes[0] = PA_POINTER;
argtypes[1] = PA_INT;
return 2;
int main(void)
double x[4] = 456543645.6786e45, 456543654, 1e345, -345.56e67;
register_printf_function ('Y', printdump, printdumpargs);
printf("%Y\n", &x, sizeof(x));
我看到它现在已经贬值了(可能没有人使用它)
https://godbolt.org/z/qKs6e1d9q
输出:
30 18 CB 5A EF 10 13 4B
00 00 00 A6 4D 36 BB 41
00 00 00 00 00 00 F0 7F
C4 5D ED 48 9C 05 60 CE
【讨论】:
printdumpargs
似乎有缩进问题,或者可能是缺少块。【参考方案3】:
没有用于您的目的的标准转换说明符,但您可以使用辅助函数和动态数组在 C99 中实现您的目标:
#include <stdio.h>
char *dump_bytes(char *buf, const void *p, size_t count)
const unsigned char *src = p;
char *dest = buf;
while (count --> 0)
dest += sprintf(dest, "%.2X", *src++);
if (count)
*dest++ = ' ';
*dest = '\0'; // return an empty sting for an empty memory chunk
return buf;
int main()
long n = 0x12345;
printf("n is at address %p with contents: %s\n",
(void *)&n,
dump_bytes((char[3 * sizeof(n)])"", &n, sizeof(n)));
return 0;
输出:n is at address 0x7fff523f57d8 with contents: 45 23 01 00 00 00 00 00
您可以使用宏进行更简单的调用:
#define DUMPBYTES(p, n) dump_bytes((char[3 * (n)])"", p, n)
int main()
char *p = malloc(5);
printf("allocated 5 bytes at address %p with contents: %s\n",
p, DUMPBYTES(p, 5));
free(p);
return 0;
【讨论】:
以上是关于使用带有 printf 的格式字符串打印可变字节数的主要内容,如果未能解决你的问题,请参考以下文章