13

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ません;いずれの場合も、「警告なし」と「一部の警告」の違いは「一部の警告」との違いよりも見つけやすいため、警告なしでコードをコンパイルすることをお勧めします。 「もう少し警告」。)

これらはすべて不十分なようで、私が見逃している何か賢いものがあるかどうか疑問に思っています。

(注:もちろん、それが実際に真実である場合、私は「いいえ、それだけです」という答えを受け入れます。)


したがって、答えは、これが実際に意図された動作であり、上記の動作よりもはるかに優れている動作を停止する方法がないということのように見えます。(Mark Bは、明示的なキャストと同じように機能する関数を記述できることを確認しまし+=た。ecatmuroperator+=は、明示的なキャストを行う関数を使用して新しい型を定義することを提案しました。)

私はマークBの答えを受け入れています。タイトルの質問に対する実際の答えは、単に「はい」です:-)。

4

2 に答える 2

1

この場合の警告のロジックは、複合演算子が実装する操作と機能的に同じであると思います。複合演算子の構文は、非常に明白な複合操作を実行することになっています。この場合、自分が何をしているかを正確に知っていることを明示的に伝えたいと思います。意図が存在することを明確にしたい場合は、コードをより明確に綴ることが常に優先されます。1回だけ記述しますが、綴りの長いバージョンを使用すると、将来の保守担当者に意図が完全に明確になります。

操作を分解し、キャストを綴ることをお勧めします。あなたのメンテナは本当に気にしないでしょう、そして私は彼らがそれが醜いと思うだろうとは思わないでしょう。

scalar_mult(short&, short)または、キャストを隠す関数を作成します。次に、明確な意図を示し、すべての表現でキャストを避けます。

最後に、警告を避けて、短いタイプを完全に回避できる場合があります。

于 2012-09-28T15:08:21.503 に答える
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

于 2012-09-28T15:17:43.760 に答える