gcc 的 -Wconversion 是否与使用比 int 短的整数类型的复合赋值(+= 等)不兼容?

Is gcc's -Wconversion incompatible with the use of compound assignment (+= etc.) with integral types shorter than int?

本文关键字:复合 赋值 不兼容 类型 整数 是否 -Wconversion int gcc      更新时间:2023-10-16

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