【问题标题】:Determine number of printf arguments确定 printf 参数的数量
【发布时间】:2016-06-21 08:15:45
【问题描述】:

是否有一个标准的 C/C++ 函数,给定 printf 格式字符串,返回它期望的参数数量?例如:

num_printf_args("%d %s") == 2;
num_printf_args("%.1f%%") == 1;
num_printf_args("%*d") == 2;

仅计算格式字符串中% 的数量将是第一个近似值,这在第一个示例中有效,但显然不适用于第二个和第三个示例。

我知道 gcc 可以做到这一点,因为在编译时它会抱怨实际传递给 printf 的参数数量(以及它们的类型)与格式字符串不匹配。

【问题讨论】:

  • 在 ISO/IEC 9899:1999(语言标准)中没有这样的功能。不完全确定:2011,但我不这么认为。它是由 GCC 实现的扩展。
  • 如果没有关于参数类型的信息,为什么会有用?
  • 它不是语言的一部分,而是特定的 gcc 扩展。请参阅 gcc's Function Attributes 中的 format
  • 按照我的理解,你有 fixed 格式字符串,printf 将从中返回 输出的字符数,你有 variadic 函数将接受可变数量的参数,但没有printf 返回预期的conversions 数量。这并不是说您不能创建一个 wrapper 来解析格式字符串的内容并返回预期的转换次数,并且如果提供了您的列表,还可以为这些参数提供类型检查。
  • @n.m. 如果没有关于参数类型的信息,为什么它会有用? 计算预期参数的数量实际上是确定参数应该是什么的先决条件。您必须先知道他们的在哪里,然后才能知道他们是什么,而知道他们在在哪里意味着知道数字。

标签: c


【解决方案1】:

没有标准函数可以做到这一点。

但是,它很容易实现。

计算后面没有另一个%% 的数量。添加1 为每个计数% 紧跟*

计算% 字符的运行时,不允许重叠。所以“%%%d”的结果应该是1(不是0,当然也不是23)。

编辑 - 下面的文本添加了来自 user694733 的评论

这对于您给出的三个示例中的格式字符串就足够了。然而,正如 cmets 中的 user694733 所指出的,这并不是全部。

一般来说,格式说明符遵循原型%[flags][width][.precision][length]specifier。上面的方法是一个起点,适用于格式字符串没有flagswidth 说明符中可能有*precision 说明符中没有*,并且忽略了length 和@ 987654338@ 字段。对于一般格式字符串,所有这些都需要考虑,并相应地解析字符串。执行此操作的工作量取决于您需要计数的稳健程度 - 例如,如果您需要检测无效的格式字符串,则需要更多的工作量。

【讨论】:

  • 没那么简单。您还需要考虑双 * 和标志的情况;例如%+*.*f。您需要从本质上实现完整的格式字符串解析器。
  • @user694733。对于 OP 提供的示例,我的回复就足够了,但我同意 - 其他不会的示例/我将添加关于限制的评论,以及其他需要尽快完成的事情。
  • 对于确定参数数量的非编译器支持,自行实现这一点并不安全。它可能会造成安全漏洞,因为几乎所有编译器都会使用堆栈内存来实现类似printf() 的函数,并且它可能允许堆栈溢出攻击。
【解决方案2】:

我不确定您为什么需要这个,但是您的问题可能可以在 this way 中解决(接受此问题的答案:Variadic macro trick)。

按照 cmets 中的建议,您可以将 printf 的调用包装到一个宏中,该宏将首先计算所需参数的数量,然后继续执行您想做的任何事情。

博文中的代码:

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N

// to verify, run the preprocessor alone (g++ -E):
VA_NUM_ARGS(x,y,z)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-28
    • 1970-01-01
    • 2018-07-19
    • 2017-06-26
    • 1970-01-01
    • 2017-11-24
    • 2013-08-09
    • 1970-01-01
    相关资源
    最近更新 更多