如何明智地解释这个编译器警告?
当我执行这个问题的代码时,我得到了这个警告:
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,在这种情况下,类型安全可能不是一个大问题。