【问题标题】:Using _Generic for printf formatting使用 _Generic 进行 printf 格式化
【发布时间】:2021-03-04 00:59:51
【问题描述】:

我发现自己经常输入错误的格式类型,不记得何时执行fLflf 等。有没有办法在@ 的帮助下执行以下操作987654324@关键字?

#define TYPE(X)   _Generic((X), float: "float", double: "double", long double: "long_double")
#define FORMAT(X) _Generic((X), float: "%f",    double: "%f",     long double: "%Lf")

printf("%s if of type %s\n", FORMAT(10.), 10., TYPE(10.));

基本上,我希望它打印出来:

10.000000 是双精度类型

有没有办法做到这一点?

我想一个速记选项是这样的:

#define TYPE(X)     _Generic((X), float: "float", double: "double", long double: "long_double")
#define STRINGIZE(X)   #X
printf("%s if of type %s\n", STRINGIZE(10.), TYPE(10.));
  1. 如果是双精度类型

【问题讨论】:

  • 大多数流行的编译器都有解析文字格式字符串的能力,并且可以警告你类型不匹配。启用它而不是弄乱宏更值得。
  • @StoryTeller-UnslanderMonica 当然可以,但这也为我自己提供了很好的文档,我可以在一个地方查看所有类型格式。
  • 重复10. 3 次的要求似乎是这件事的一个缺点。

标签: c c-preprocessor


【解决方案1】:

printf 中的格式说明符本身不能作为参数。它们必须是格式字符串的一部分。

您可以通过将FORMAT 宏设置为整个格式字符串来执行此操作,以便一次调用printf 以打印值。然后你可以再打电话给剩下的:

printf(FORMAT(10.), 10.);
printf(" is of type %s\n", TYPE(10.));

但是,正如 cmets 中所述,现代编译器足够聪明,可以检测 printf 格式字符串与其参数之间的不匹配。因此,依靠它也同样有效。

【讨论】:

  • 如何组合成:#define PPRINT(X) printf(FORMAT(X), X); printf(" is of type %s\n", TYPE(X))PPRINT(10.);。这样做有什么缺点吗?
【解决方案2】:

格式类型错误,不记得何时执行 f 或 Lf 或 lf 等。

请注意,对于floatdoublell 都有效,因为float 扩充到... 参数被提升为doublel 是可选的 printf 说明符 "%f" 和朋友:fFeEgGaA

printf("%f\n", 1.2f);
printf("%f\n", 3.4);
printf("%lf\n", 5.6f); // unusual, yet OK
printf("%lf\n", 7.8);

要使用_Generic 进行打印,也许是Formatted print without the need to specify type matching specifiers using _Generic

float/double 使用不同的打印说明符的一个有用的原因是精度。

#define ForD(X)   _Generic((X), float: FLT_DECIMAL_DIG-1, double: DBL_DECIMAL_DIG-1)
printf("%.*e\n", ForD(f), f);  // Best if `f` is not be an expression.

【讨论】:

  • 这很简洁——您能解释一下ForD(X) 的工作原理吗?这是否指定了精度,例如基于FLT|DBL_DECIMAL_DIG%.4f 然后*e 做了什么?
  • @carl.hiass ... "*e", precession, fp_value); 以指数表示法打印fp_value,右边有precession 数字,如sd.dddddd...dddesdd(s:符号,d:数字)。 float 信息最多约 9 位,double 至 17。请研究 printf() 了解详情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-06
  • 2019-07-01
  • 1970-01-01
  • 2017-03-16
  • 2021-05-17
  • 2019-10-19
  • 1970-01-01
相关资源
最近更新 更多