如何在C语言中编写自己的新格式说明符?

4

在C语言中,是否可以编写新的格式说明符?例如,假设%g是一个格式说明符,它可以从无符号整数等效值中以A.B.C.D格式打印IP地址。

int ip_addr = Some integer

printf("ip address = %g", ip_addr);

输出:以A.B.C.D格式打印IP地址


1
你可以在[tag:c]中写任何你想要的内容,但是你不能向标准库函数printf()添加格式说明符。不过,你可以编写一个可变参数函数,为每个格式说明符调用printf()和自定义程序来处理你的说明符,此外,你可以让你的程序调用你的printf()函数并使用相同的名称。但我不建议这样做。 - Iharob Al Asimi
3
步骤1)避免使用现有的格式说明符,例如"%g",它用于double类型。 - chux - Reinstate Monica
嗯,IP地址有32位应该是无符号的。使用“int”既不好用也不合适。 - too honest for this site
4个回答

7

您需要重新实现printf函数(更准确地说是其格式解析函数)。您可以在支持IP地址的函数内部包装printf,或者执行以下操作:

#define FMT_IP "%d.%d.%d.%d"
#define FMT_IP_ARG(ip) getA(ip), getB(ip), getC(ip), getD(ip)

getX函数或宏从表示IP地址的整数中获取X部分。

然后:

printf("ip address = " FMT_IP "\n", FMT_IP_ARG(ip));

getAgetB等是什么? - Jabberwocky
1
@MichaelWalz请看原帖中的A、B、C和D。问题是关于编写格式说明符,而不是从int获取这些值。 - mikedu95
也许你应该在问题中澄清这一点。 - Jabberwocky
完成了Michael。谢谢。 - mikedu95

2
我会选择@chux的答案,如果你知道需要多大的临时缓冲区,这个方法就简单又便携。

然而,如果你使用 GNU 库(glibc),你可以用新的格式说明符扩展printf。强烈建议使用大写字母作为格式代码,因为几乎所有小写格式代码都在使用中,其余的可能会被未来的 C/Posix 标准使用。这个功能在glibc 手册中有文档。

基于 GNU 功能,为 BSD 库编写了一个类似的兼容性很好的工具。显然,在 Mac OS X 上可用,但我不能保证这一点。我在苹果的在线手册xprintf(3)xprintf(5)中找到了它。

上述文档中有示例。

2

添加新的格式说明符需要重新编写printf()函数,或者创建一个自己的函数来处理新的格式说明符,并调用它。这两种方法都很困难。


另一种替代方法是使用"%s"并创建一个自己的函数来组成一个字符串。

在C99或更高版本中,可以使用复合字面量来形成所需的缓冲区空间。

#include <stdio.h>
#define MYIP_N 16
#define MYIP(ip) myip((char [MYIP_N]){""}, (ip))

char *myip(char *dest, int ip) {
  snprintf(dest, MYIP_N, "%d.%d.%d.%d", (ip >> 24) & 255, (ip >> 16) & 255,
      (ip >> 8) & 255, (ip >> 0) & 255);
  return dest;
}


int main(void) {
  int ip1 = 0x01020304;
  int ip2 = 0x05060708;
  printf("%s %s\n", MYIP(ip1), MYIP(ip2));
  return 0;
}

输出

1.2.3.4 5.6.7.8

这适用于printf()fprintf()sprintf()甚至puts()
puts(MYIP(ip1));

1.2.3.4

0

虽然您无法更改标准库函数,但可以编写一个包装函数,该函数将接受%g并调用printf


我想知道你是如何编写这样的函数的。在程序中调用 printf (或 vprintf) 不是一件容易的事情。 - Jérôme Pouiller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接