GCCからの-Wconversion警告への対処方法
-
10-07-2019 - |
質問
GCCの-Wconversion警告フラグを使用してプロジェクトを構築しています。 (gcc(Debian 4.3.2-1.1)4.3.2)64ビットGNU / Linux OS /ハードウェア。どこでタイプを混合したか、どのタイプを使用すべきかについて明確さを失ったかを識別するのに役立ちます。
警告をアクティブにする他のほとんどの状況ではあまり役に立たないので、これらをどのように処理するのかを尋ねています:
enum { A = 45, B, C }; /* fine */
char a = A; /* huh? seems to not warn about A being int. */
char b = a + 1; /* warning converting from int to char */
char c = B - 2; /* huh? ignores this *blatant* int too.*/
char d = (a > b ? b : c) /* warning converting from int to char */
上記のテストの予期しない結果( a
と c
のケース)のため、これらの違いについても説明を求めています。
編集:そして、これらをすべて(char)
でキャストして警告を防ぐのは過剰なエンジニアリングですか?
Edit2:いくつかの追加のケース(上記のケースに続く):
a += A; /* warning converting from int to char */
a++; /* ok */
a += (char)1; /* warning converting from int to char */
それ以外に、私が求めているのは主観的であり、一部の開発者が all 警告の削除を提唱していると考える場合、このような場合に他の人がどのように変換警告に対処するかを聞きたいです。
やえ:
可能な解決策の1つは、 char
sではなく int
sを使用することです。実際、より多くのメモリが必要なだけでなく、次のコードで示すように、速度も遅くなります。数学式は、 -Wconversion
でビルドされたときに警告を取得するためだけにあります。変換のため、 char
変数を使用するバージョンは int
sを使用するバージョンよりも実行が遅いと想定しましたが、私の(64ビットデュアルコアII)システムでは int
バージョンは遅いです。
#include <stdio.h>
#ifdef USE_INT
typedef int var;
#else
typedef char var;
#endif
int main()
{
var start = 10;
var end = 100;
var n = 5;
int b = 100000000;
while (b > 0) {
n = (start - 5) + (n - (n % 3 ? 1 : 3));
if (n >= end) {
n -= (end + 7);
n += start + 2;
}
b--;
}
return 0;
}
-DUSE_INT
をgccに渡して、上記のスニペットのintバージョンをビルドします。
解決
/ * int * /
と言うとき、それについての警告を与えているということですか? -Wconversion
を使用したgcc 4.0.1または4.2.1のこのコードでは、警告はまったく表示されません。コンパイラはこれらの列挙型を定数に変換しています。コンパイル時にすべてがわかっているため、警告を生成する理由はありません。コンパイラーはすべての不確実性を最適化できます(以下は4.2.1のIntelです):
movb $45, -1(%rbp) # a = 45
movzbl -1(%rbp), %eax
incl %eax
movb %al, -2(%rbp) # b = 45 + 1
movb $44, -3(%rbp) # c = 44 (the math is done at compile time)
movzbl -1(%rbp), %eax
cmpb -2(%rbp), %al
jle L2
movzbl -2(%rbp), %eax
movb %al, -17(%rbp)
jmp L4
L2:
movzbl -3(%rbp), %eax
movb %al, -17(%rbp)
L4:
movzbl -17(%rbp), %eax
movb %al, -4(%rbp) # d = (a > b ? b : c)
これは、最適化をオンにしないで行われます。最適化により、コンパイル時にbとdが計算され、最終値がハードコードされます(実際に必要な場合)。ポイントは、gccがすでに解決済みであり、すべての可能な値が char
に収まるため、ここで問題が発生しないことです。
編集:これを多少修正させてください。 b
の割り当てでエラーが発生する可能性があり、コンパイラーは確実であってもそれをキャッチしません。たとえば、 b = a + 250;
の場合、 b
がオーバーフローすることは確実ですが、gccは警告を発行しません。これは、 a
への割り当てが正当であり、 a
が char
であり、数学が正しくないことを確認するのはコンパイラの問題ではないためです。実行時にオーバーフローしません。
他のヒント
おそらく、コンパイラーはすべての値がcharに収まることを既に確認できているので、警告を表示しません。コンパイルの開始時に enum
が解決されることを期待しています。