ProgrammingC開発者

C言語の式における型変換(型の昇格、型の変換)のルールは何ですか?予期しないエラーとその解決策の例を示してください。

Hintsage AIアシスタントで面接を突破

回答

C言語の式では、しばしば*(型の昇格)*(type promotion、type conversion)が行われ、これは標準によって規制されています。

  • 整数の昇格: より小さなビット幅の型(たとえば、charshort)は、算術演算の前に自動的に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);

回答: 変数iunsigned intに変換され、最終的な値は非常に大きくなります。なぜなら、内部では結果が1U + (unsigned int)-2Uとして処理され、UINT_MAX(4294967295)に近い数値が得られるからです。フォーマットをintで表示しない限り、出力は負の数になります。それ以外の場合はゴミデータが表示されます。

このテーマの詳細を知らなかったための実際のエラーの例


物語

画像の強度の平均値を計算する際にintunsigned intを間違えて使用しました。負の値が正しく符号なしに転送され、巨大な数になり、画像のバッファがオーバーフローしました。


物語

組み込みファームウェアでは、文字列の長さをsize_tで計算し、配列のインデックスをintを介して行いました。配列の境界を越えないようにする条件を確認する際に、int i >= size_t lenを比較しており、長い文字列に対するロジックが壊れ、異なる型(size_tは符号なし)を比較する際にバグが発生しました。


物語

金融プロジェクトの開発者は、負の数の剰余を%で計算していましたが、負のオペランドの場合の結果の符号は実装に依存することを忘れていました。ある環境では結果が正で、別の環境では負となり、計算が定期的に「ずれて」いました。