gcc 有一个有用的标志-Wconversion
,当从较宽类型到较窄类型的隐式转换时会产生警告,可能会丢失信息。不幸的是,它有以下......无益的......行为。
考虑这个程序:
int main(void) {
short x = 1;
x = x+x;
return 0;
}
用 -Wconversion 编译它会产生
nonsense.c: In function 'main':
nonsense.c:3:8: warning: conversion to 'short int' from 'int' may alter its value [-Wconversion]
这很公平;在大多数平台上,如果发生这种情况,这将做一些你可能不会想到的事情x==0x8000
。(您收到此警告的实际机制:操作数+
受“通常的算术转换”的影响,这会将它们扩大为 int;因此结果也是 int 类型;然后分配回x
是从更广泛的隐式转换到更窄的类型。)但是假设您确实期望并打算这样做。(您正在模拟 16 位处理器或 16 位移位寄存器;或者您知道x
此代码中可能值的范围,并且它永远不会溢出。)您可以通过显式强制转换来告诉编译器:
int main(void) {
short x = 1;
x = (short)(x+x);
return 0;
}
然后它就不会抱怨了。
到目前为止,一切都很好。但是,如果导致问题的赋值是复合赋值 - +=
, *=
,<<=
等 - 那么据我所知,没有办法摆脱这个警告,因为代码中没有任何一点可以您可以插入显式演员表。
这意味着,例如,你不能拥有所有
- -Wconversion 在您项目的顶级编译器标志中,以捕获它打算处理的所有真正错误。
- 复合赋值运算符代码中任何位置的任何实例都适用于短于
int
. - 无警告构建。
这似乎很伤心。
所以,问题是:有没有解决这个问题的好方法?我可以看到以下方式:
- 用于
#pragma GCC diagnostic ...
禁用尽管没有错误但已知会引发警告的代码位中的警告。(缺点:丑陋,特定于编译器。) - 将复合赋值扩展为更长的单个赋值并插入显式强制转换。(缺点:超级丑。)
- 关掉
-Wconversion
。(缺点:此警告在其他地方很有用。) - 忍受警告。(缺点:与 using 不兼容
-Werror
;在任何情况下,让您的代码在没有警告的情况下编译是一种很好的做法,因为“无警告”和“某些警告”之间的区别比“某些警告”和“某些警告”之间的区别更容易发现“更多警告”。)
所有这些似乎都不令人满意,我想知道我是否缺少更聪明的东西。
(注意:如果这确实是事实,我当然会接受“不,就是这样”的答案。)
因此,看起来答案似乎是这确实是预期的行为,没有办法阻止它,这比上面列出的要好得多。(Mark B 观察到您可以编写一个与显式转换相同+=
但具有相同功能的函数。ecatmur 建议使用operator+=
函数定义一个新类型来执行显式转换。)
我接受马克 B 的回答;标题中问题的实际答案只是“是”:-)。