如何明智地解释这个编译器警告?

How to wisely interpret this compiler warning?

当我执行这个 的代码时,我收到了这个警告:

warning: format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]
printf("P-Q: %d, P: %d, Q: %d", (p - q), p, q);
             ~^                 ~~~~~~~
             %ld

作为条件反射修复,我使用 %ld 来打印两个指针的减法。编译器同意了。

幸运的是,我看到另一个用户的评论提到应该使用%td,因为减法的结果类型是ptrdiff_t。这 证实了这一说法。

现在从stddef.h的GCC头文件中,我可以看出这些类型在这种情况下是等价的:

typedef __PTRDIFF_TYPE__ ptrdiff_t;
#define __PTRDIFF_TYPE__ long int

但是,我只是想建议对 OP 进行错误的(或多或少)修复,使用 %ld,而不是 %td

有什么方法可以让我明白仅靠编译器警告是不够的?或者也许明智地解释了警告本身,而不仅仅是做出反应。

我觉得你看不出来。这取决于编译器作者的intent/caution/smartness。

也许他决定他将永远支持 %ld,而 %td 是预期的,或者他只是 unaware/unable/unwilling 给出了更多 detailed/proper 的信息。如有疑问,您的最后一招就是标准。

这似乎不是一个可移植的结构,对于 "orthodoxy" 你应该支持两种格式说明符。

这里的关键是:首先不要在 printf 中进行任何形式的算术运算。将算法与 GUI 分开。

printf("%d", p - q) 之类的代码非常危险,不仅因为您可能会在逻辑上弄错类型,还因为 C 可能 "do you a favour" 并通过隐式类型提升悄悄更改类型。 .

此外,大多数编译器不会对错误的格式说明符发出警告。这是 C 历史上相对较新的事物,因为编译器不需要在此处显示诊断消息。这只是 gcc 的一个额外功能。

如何避免错误?这些功能本质上是危险的——事实就是如此,每个人都知道这一点。就给人类造成的错误总成本而言,printf 和 scanf 函数族可能是编程史上最有害的函数。那么你应该怎么做:

  • 尽可能避免 stdio.h 并使其远离生产质量代码。可移植性并不总是比健壮的代码更重要——有时最好使用原始控制台 API。通常避免使用可变参数列表函数。
  • 如果无法避免,请将 stdio.h 的 "GUI" 部分包装在一个单独的文件中,无论如何您都应该这样做。不要将 printing/input 与算法混用。创建一个使用指针的接口。
  • 现在是 2018 年,不是 1970 年:首先不要编写控制台界面。是的,我知道……有很多旧垃圾仍然漂浮在周围,需要维护。但是如今,控制台功能应该主要用于调试目的和学习 C 的新手,在这种情况下类型安全可能不是一个大问题。