gcc 的 -Wconversion 是否与使用比 int 短的整数类型的复合赋值(+= 等)不兼容?
Is gcc's -Wconversion incompatible with the use of compound assignment (+= etc.) with integral types shorter than int?
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
。(不利:此警告在其他地方很有用。) - 忍受这些警告。(缺点:与使用
-Werror
不兼容;在任何情况下,让代码编译时完全没有警告都是一种好的做法,因为"没有警告"answers"一些警告"之间的区别比"一些警告和更多警告"之间更容易发现。)
所有这些似乎都不令人满意,我想知道我是否缺少了更聪明的东西。
(注意:如果事实确实如此,我当然会接受"不,就这样"的回答。)
因此,答案似乎是这确实是预期行为,没有办法阻止它,这比上面列出的要好得多。(Mark B观察到,您可以编写一个与+=
相同但具有显式强制转换的函数。ecatmur建议定义一个具有operator+=
函数的新类型来执行显式强制转换器。)
我接受马克B的回答;标题中问题的实际答案只是"是":-)。
我假设在这种情况下发出警告的逻辑是,它在功能上与复合运算符实现的操作相同。复合运算符语法应该做一个非常明显的复合运算,在这种情况下,你想明确地说你确切地知道你在做什么。当你想清楚地表明你的意图存在时,更明确地拼写代码总是成功的:你只写了一次,但拼写更长的版本会让未来的维护人员完全清楚你的意图。
我建议你把操作分解,然后把演员阵容拼出来。你的维护人员真的不会介意,我怀疑他们会认为这很难看。
或者,创建一个scalar_mult(short&, short)
函数来隐藏强制转换。然后,您在每个表达式中都显示出明确的意图和。
最后,您可以完全避免较短的类型,从而避免警告。
在RHS上使用用户定义的类型将起作用:
struct cast_result {
int t;
};
char &operator+=(char &l, cast_result r) { return l = static_cast<char>(l + r.t); }
int main() {
char c = 'a';
c += cast_result{2};
}
你可以用用户定义的文字等来美化它,但它仍然相当丑陋。
我想问一下为什么你需要对窄类型进行算术是公平的。在C的设计中,通常假设窄类型的效率低于或可能低于int
。
- C 复合赋值运算符 ^= 平均值
- 复合赋值运算符C++概念
- 在未初始化的变量上使用复合赋值运算符(+=, ..)不是C++中的UB?
- 复合赋值运算符是否不如 C++ 精确?
- 重载C++中的复合赋值运算符
- C++中重载复合赋值运算符不会更改变量
- 复合赋值的左侧表达式是未初始化的值.计算出的值也将是垃圾
- 枚举的复合赋值运算符真的应该根据其关联的算术运算符来定义吗?
- C++ 布尔复合赋值线程安全
- 复合赋值运算符重载
- gcc 的 -Wconversion 是否与使用比 int 短的整数类型的复合赋值(+= 等)不兼容?
- 在复合赋值运算符中强制转换
- 复合赋值到布尔值安全吗?
- 重载复合赋值运算符
- 复合赋值和添加运算符重载
- 使用复合赋值运算符解决转换警告
- 复合赋值运算符的类型/类型转换?(例如*=(星形等于))
- 枚举上复合赋值运算符的运算符重载
- 复合赋值和运算符之间的区别
- 使用重载复合赋值操作符时的运行时错误