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

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

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

作为reflection修复,我使用%ld来打印两个指针的减法。 编制者同意了。

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

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

 typedef __PTRDIFF_TYPE__ ptrdiff_t; #define __PTRDIFF_TYPE__ long int 

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

有没有办法让我理解单独的编译器警告是不够的? 或者也许明智地解释警告本身,而不仅仅是反应。

我认为你不能说。 这取决于编译器编写器的意图/警告/智能。

也许他决定他总是支持%ld预期%td ,或者他可能只是不知道/不能/不愿意提供更详细/正确的消息。 如有疑问,您的最后手段是标准。

这似乎不是一个可移植的构造,对于“正统”,你应该支持两种格式说明符。

这里的关键是:首先不要在printf中进行任何forms的算术运算。 从GUI分离算法。

诸如printf("%d", p - q)是非常危险的,不仅因为你可能在逻辑上得到错误的类型,而且因为C可能“帮你一个忙”并通过隐式类型提升默默地改变类型。 例子 。

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

如何避免错误? 这些function本身就很危险 – 就是这样,人人都知道。 printf&scanf系列函数可能是编程史上编写的最有害的函数,就人类造成的总bug成本而言。 所以你应该怎么做:

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