См. раздел 4.1.5 спецификации языка C# 4.0. В частности, интересует:
C# поддерживает девять целочисленных типов: sbyte, byte, short, ushort, int, uint, long, ulong и char. [текст опущен]
Унарные и бинарные операторы целочисленного типа всегда работают с 32-битной точностью со знаком, 32-битной точностью без знака, 64-битной точностью со знаком или 64-битной точностью без знака:
[опущены пункты списка]
Для двоичных операторов +, –, *, /, %, &, ^, |, ==, !=, >, ‹, >= и ‹= операнды преобразуются в тип T, где T — первый из int, uint, long и ulong, который может полностью представлять все возможные значения обоих операндов. Затем операция выполняется с точностью типа T, а тип результата — T (или bool для реляционных операторов). Не допускается, чтобы один операнд имел тип long, а другой — тип ulong с бинарными операторами.
Операции, использующие short, повышаются до int, и эти операции снимаются для их аналогов, допускающих значение NULL. (Это ведет к разделам 7.3.6.2 и 7.3.7)
Хорошо, это по дизайну, но до сих пор не понимаю, почему они это делают, они слишком оптимизировали строку, добавляя слишком много, почему оставили числа в покое и добавили больше кода для этого простого сравнения
Просто так спроектирован язык с учетом оптимизации в современной архитектуре. Не конкретно в этом контексте, но рассмотрите слова Эрика Липперта, как указано здесь
Арифметика никогда не делается в шортах на C#. Арифметика может быть выполнена в целых, uint, длинных и улонговых числах, но арифметика никогда не выполняется в шортах. Шорты превращаются в int, а арифметика выполняется в int, потому что, как я уже говорил, подавляющее большинство арифметических вычислений укладывается в int. Подавляющее большинство не влезает в шорт. Короткая арифметика, возможно, медленнее на современном оборудовании, оптимизированном для целых чисел, и короткая арифметика не занимает меньше места; это будет сделано в целых или длинных числах на чипе.
Ваше последнее обновление:
Я ожидаю, что компилятор сделает простую проверку с помощью .HasValue if (cTestA.HasValue){}, по крайней мере, это то, что я делаю в своем коде после того, как обнаружу это преобразование. Так вот что я действительно не понимаю, почему бы не сделать это простое мышление, но добавить весь этот дополнительный код. Компилятор всегда пытается оптимизировать код — почему бы не использовать эту простую проверку .HasValue. Я что-то здесь точно упускаю...
Мне придется обратиться к эксперту по компиляторам, чтобы сказать, почему они решили пойти на преобразование вместо немедленной проверки HasValue, за исключением того, что может быть просто порядок операций. Спецификация языка говорит, что операнды бинарных операторов продвигаются, и это то, что они сделали в предоставленном фрагменте. Позже в спецификации языка говорится, что проверки с x == null
, где x — тип значения, допускающий значение NULL, могут быть преобразованы в !x.HasValue
, и это также то, что они сделали. В скомпилированном коде, который вы представили, числовое продвижение просто имело приоритет над поведением, допускающим значение NULL.
Насчет того, что компилятор всегда пытается оптимизировать код, опять же, специалист может пояснить, но это не так. Есть оптимизации, которые он может сделать, а другие, возможно, зависят от джиттера. Существуют оптимизации, которые либо компилятор, либо дрожание могут выполнять или не выполнять в зависимости от того, является ли это сборкой отладки или сборки выпуска, с подключенным отладчиком или без него. И, несомненно, есть оптимизации, которые они могли бы сделать, но они просто решили не делать их, потому что затраты и выгоды не учитываются.
person
Anthony Pegram
schedule
09.02.2012