次のコードでは、unsigned char が int より小さいと仮定します。
int f(void) { int i = -2; unsigned char uc = 1; return (i + uc) < 17; }
このコードは、-xtransition オプションを使用したときに、コンパイラが次の警告を発行する原因になります。
line 6: warning: semantics of "<" change in ISO C; use explicit cast
加算の結果の型は int (値保持) または unsigned int (符号なし保存) です。しかし、どちらの場合でもビットパターンは同じです。2 の補数を使用するマシンでは、次のようになります。
i: 111...110 (-2) + uc: 000...001 ( 1) =================== 111...111 (-1 or UINT_MAX)
このビット表現は、int では -1 に対応し、unsigned int では UINT_MAX に対応します。したがって、結果の型が int の場合、符号付きの比較が使用され、「小さい」のテストは真になります。結果の型が unsigned int の場合、符号なしの比較が使用され、「小さい」のテストは偽になります。
キャストの加算を使用すると、2 つの動作のうち、どちらを希望するかを指定できます。
value preserving: (i + (int)uc) < 17 unsigned preserving: (i + (unsigned int)uc) < 17
異なるコンパイラが同じコードに対して異なる意味を選択したため、この式は曖昧になる可能性があります。キャストの加算を使用することにより、コードが読みやすくなると同時に、警告メッセージも発行されなくなります。
同じ動作が、ビットフィールド値の拡張にも適用されます。ISO C では、int または unsigned int ビットフィールド内のビットの数が int 中のビットの数よりも少ない場合、拡張される型は int です。それ以外の場合、拡張される型は unsigned int です。ほとんどの古い C コンパイラでは、明示的な符号なしビットフィールドの場合、拡張される型は unsigned int です。それ以外の場合は int です。
この場合も、キャストを使用することにより、曖昧になることを防ぐことができます。