C言語の式では、しばしば*(型の昇格)*(type promotion、type conversion)が行われ、これは標準によって規制されています。
char、short)は、算術演算の前に自動的にintまたはunsigned intに変換されます。例:
unsigned short a = 65535; signed short b = -1; printf("%d\n", a + b); // 変換に依存します!
推奨事項: オペランドの型には注意を払い、特にビット操作、配列の長さ、インデックスに対しては、符号付き型と符号なし型の不明確な混合を避けるようにしてください。
以下のコードスニペットは何を出力しますか?
unsigned int u = 1; int i = -2; printf("%d\n", u + i);
回答: 変数iはunsigned intに変換され、最終的な値は非常に大きくなります。なぜなら、内部では結果が1U + (unsigned int)-2Uとして処理され、UINT_MAX(4294967295)に近い数値が得られるからです。フォーマットをintで表示しない限り、出力は負の数になります。それ以外の場合はゴミデータが表示されます。
物語
画像の強度の平均値を計算する際に
intとunsigned intを間違えて使用しました。負の値が正しく符号なしに転送され、巨大な数になり、画像のバッファがオーバーフローしました。
物語
組み込みファームウェアでは、文字列の長さを
size_tで計算し、配列のインデックスをintを介して行いました。配列の境界を越えないようにする条件を確認する際に、int i >= size_t lenを比較しており、長い文字列に対するロジックが壊れ、異なる型(size_tは符号なし)を比較する際にバグが発生しました。
物語
金融プロジェクトの開発者は、負の数の剰余を
%で計算していましたが、負のオペランドの場合の結果の符号は実装に依存することを忘れていました。ある環境では結果が正で、別の環境では負となり、計算が定期的に「ずれて」いました。