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

时间:2012-09-28 13:53:53

标签: c++ c gcc casting warnings

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类型;然后分配回{{ 1}}是从较宽类型到较窄类型的隐式转换。)但假设您期望并打算这种行为。 (您正在模拟一个16位处理器或一个16位移位寄存器;或者您知道此代码中x的可能值的范围,它永远不会溢出。)您可以通过以下方式告诉编译器投入一个明确的演员:

x

然后它不会抱怨。


到目前为止,这么好。但是,如果造成问题的作业是复合作业 - int main(void) { short x = 1; x = (short)(x+x); return 0; } +=*=等等 - 那么就我所知,没有办法摆脱这个警告,因为代码中没有任何可以插入显式强制转换的点。

这意味着,例如,你不能拥有所有

  • - 项目顶级编译器标志中的转换,以捕获它的所有真正错误。
  • 复合赋值运算符代码中任何位置的任何实例都应用于短于<<=的整数类型。
  • 无警告构建。

这似乎很难过。


所以,问题:有解决这个问题的好方法吗?我可以看到以下方法:

  • 使用int禁用警告,尽管没有错误,但已知会引发警告。 ( Downside :丑陋,特定于编译器。)
  • 将化合物分配扩展为更长的单个分配并插入显式强制转换。 (下行:非常丑陋。)
  • 关闭#pragma GCC diagnostic ...。 (下行:此警告在其他地方很有用。)
  • 忍受警告。 (下行:与使用-Wconversion不兼容;在任何情况下,最好不要在没有警告的情况下编译代码,因为“无警告”和“某些警告”之间的区别是比“一些警告”和“更多警告”之间的区别更容易发现。)

所有这些看起来都不尽如人意,我想知道是否有更聪明的东西让我失踪。

(注意:当然,如果这实际上是真理,我会接受“不,那就是”答案。)


所以,看起来好像答案是这确实是预期的行为,并且没有办法阻止它比上面列出的要好得多。 (Mark B观察到你可以编写一个与-Werror相同的函数,但是使用显式转换.ecatmur建议定义一个带有+=函数的新类型来进行显式转换。)

我接受马克B的回答;标题中问题的实际答案只是“是”: - )。

2 个答案:

答案 0 :(得分:1)

我认为在这种情况下警告的逻辑是它在功能上与复合运算符实现的操作相同。复合运算符语法应该做一个非常明显的复合操作,在这种情况下,你想要明确地说你确切知道你在做什么。当你想明确表示存在意图时,更明确地拼写出来的代码总是胜出:你只是写了一次,但是更长的拼写版本将使未来的维护者明白你的意图。

我建议只是去复制操作并拼出演员阵容。你的维护者真的不介意,我怀疑他们会认为这很难看。

或者,创建一个scalar_mult(short&, short)函数来隐藏演员表。然后你显示明确的意图避免每个表达式中的强制转换。

最后,你可以完全避免使用较短的类型,避免警告。

答案 1 :(得分:1)

在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效率低或效率低。