ushortを多用したC#ソースをいじっているうちに気付きました。
C#で記述された以下のソースコード断片があるとします。
ここの2行目を以下のように置き換えることができ、同じ結果が得られます。
しかし、以下のように書き換えるとコンパイルエラーになり、
エラー内容は以下の通りです。
- エラー 1 型 'int' を 'ushort' に暗黙的に変換できません。明示的な変換が存在します。(cast が不足していないかどうかを確認してください)
intよりも小さいビットサイズの型を使うと、たぶんどれでも同じような現象が起きるだろうと思います。intならx = x + 1;への置き換えも上手く行きます。
WHY? §
あらためて調べてみると興味深いことに、x++;とx += 1;とx = x + 1;の挙動の根拠は全て違います。
まず、x = x + 1;についてはC#には16bit/8bitの加算が存在しない問題で述べたように、ushortの加算が存在しないため"x + 1"の型はintになり、intからushortへの暗黙変換が存在しないためにエラーになります。
次に、x += 1;ですが、これは複合代入に対する以下のルールによって記述可能になっています。つまり暗黙的にキャストが補われています。
• 選択された演算子が定義済みの演算子で、選択された演算子の戻り値の型を x の型に "明示的に" 変換でき、y を x の型に "暗黙に" 変換できる場合または演算子がシフト演算子の場合、演算は x = (T)(x op y) として評価されます。ただし、T は x の型で、x は 1 回だけ評価されます。
最後にx++;ですが、これは以下のように"+"よりも多くの型に対する演算子が用意されているために、記述可能となっています。
sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal の各型およびすべての列挙型には、定義済みの ++ 演算子と -- 演算子があります。
ちなみに、生成したバイナリを逆アセンブルして見たところ、どれも同じでした。定義済のushort型++演算子があっても、ILレベルに落ちるときにはやはり32bit加算を経由する、ということなのでしょう。たぶん。
感想 §
ここ数年、毎日のようにC#のコードを書いていましたが、こういう基本的な部分にこのような問題があったとは。かなり新鮮です。