从数据类型推断格式说明符?

3

是否有可能以编程方式推断数据类型的格式说明符?例如,如果打印是针对长整型的,则自动执行以下操作:

printf("Vlaue of var is <fmt_spec> ", var);

我认为这样做可以减少开发者的一些错误,例如:

printf("Name is %s",int_val); //Oops, int_val would be treated as an address

printf("Name is %s, DOB is",name,dob); // missed %d for dob

printf("Name is %s DOB is %d", name);//Missed printing DOB

我知道后面两个选项确实有警告,但是如果出现错误会不会更好,因为在大多数情况下这将是有问题的?或者我是否遗漏了什么或者已经有已经存在的结构来做到这一点?


1
一些编译器(如GCC、Clang)会对格式和参数不匹配发出警告。但是回答你的问题:实际上不可能。C语言没有内置的内省反射能力。在运行时,你不能以标准的方式获取数据类型。 - Some programmer dude
1
此外,使用GCC和Clang,您可以轻松地将特定的警告转换为错误。或者将所有警告都转换为错误,然后针对特定的警告禁用错误提示。 - Some programmer dude
1
由于程序员创建变量,因此程序员应该知道变量的类型,因此责任在调用者身上。没有很好的编程方法来处理格式说明符。 - user7851115
1
理论上是可能的。我相信可以使用可变参数模板和constexpr格式字符串扫描来完成。这不是一项简单的任务,收益也不确定,但是它是可能的。如果您真的关心类型正确性,应该使用流。 - Michaël Roy
1
@MichaëlRoy 这个问题是关于C语言的。 - Eugene Sh.
显示剩余6条评论
2个回答

2
从数据类型推导格式说明符吗? 不行
正如melpomene所述:
“格式说明符不仅适用于类型。例如,%o和%x都使用unsigned int;%e、%f和%g都使用double;%d、%i和%c都使用int。这就是为什么你不能(通常)从参数中推导它们的原因。”
关键在于如果存在这样的功能,那么它会将unsigned int推导为%o或%x,例如?等等……
关于某些情况是否应该发出警告或错误,您应该考虑在中如何进行转换以及允许某些操作是否有意义。在GCC中,您当然可以将警告视为错误:
-Werror
Make all warnings into errors.

-Werror=
Make the specified warning into an error. The specifier for a warning is appended; for example -Werror=switch turns the warnings controlled by -Wswitch into errors. This switch takes a negative form, to be used to negate -Werror for specific warnings; for example -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect.

The warning message for each controllable warning includes the option that controls the warning. That option can then be used with -Werror= and -Wno-error= as described above. (Printing of the option in the warning message can be disabled using the -fno-diagnostics-show-option flag.)

Note that specifying -Werror=foo automatically implies -Wfoo. However, -Wno-error=foo does not imply anything.

你可以在这里阅读:here

1

是否可以通过编程方式推断数据类型的格式说明符?

使用printf()不容易也不直接,但是可以使用_Generic对一组有限的类型进行限制。

这可以通过多种方式实现,并且可以与*printf()一起使用,但很困难。然而,在此示例中,我发现了一种类似的方法来打印数据,而无需指定单个格式说明符:
使用_Generic无需指定类型匹配说明符的格式化打印
注意:此代码存在关于指针数学的编码漏洞,我已经修补了它,但没有发布。

GPrintf("Name is ", GP(name), " is ", GP(dob), GP_eol);

关键是使用_Generic(parameter)来控制所选用的代码,将类型转换为文本,宏GP(x)被分为两部分:一个字符串和x。然后GPrintf()解释参数。
这类似于@Michaël Roy的评论,但仍然保持在C而不是C ++中。

有一个关于_Generic的缺陷报告。一些解释将留给实现。它也不能像应该的那样与例如size_t一起使用,后者是标准类型的typedef,但使用不同的转换类型说明符。 - too honest for this site
@Olaf 关于“size_t是一个typedef”的问题,可以使用多个 _Generic 级别来处理。例如,顶层使用 unsigned, unsigned, long, unsigned long longdefaultdefault 使用第二级 _Generic_,其中包含 size_t。这并不总是提供 z,但允许代码区分其是否重要。换句话说,可以获得可比较的限定符。 - chux - Reinstate Monica
请阅读6.5.1.1p2:“……在同一通用选择中,没有两个通用关联应指定兼容类型……”-您是否不同意别名typedef unsigned int size_t;unsigned int兼容?请阅读报告;还有更多问题。它明确列出了clang和gcc作为非相同的实现。除此之外:这对于不存在的问题来说过于混淆。 C是静态类型的,所有类型在编译时都已知,并且打印通常使用已知类型。特殊输出需要额外的注意(如链接的示例所示)。解决方案正在寻找问题。 - too honest for this site
@Olaf,我并不是建议在同一个通用选择中使用 size_tunsigned - 而是在不同的级别上。简洁的例子:`#define info2(X) _Generic((X),
size_t: "z",
default: "?"
)#define info(X) _Generic((X),
unsigned long long: "ull",
unsigned long: "ul",
unsigned: "u",
default: info2(X)
)int main() { size_t sz; puts(info(sz)); unsigned u; puts(info(u)); }`
- chux - Reinstate Monica
好的,可能会起作用。但是如果size_t是编译器额外定义的类型呢?例如,gcc定义了许多内部类型和宏来使头文件更清晰(例如以这种方式定义INT_MIN等)。老实说:你真的建议这样做吗?如果你只有一把锤子,那么每个问题都看起来像一颗钉子。有些问题不适合使用锤子。并且如果输出很多,像Python这样的动态语言绝对是更好的选择。 - too honest for this site
显示剩余2条评论

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