Почему инициализация массива всегда прибегает к int?
Чтение всех возможных синтаксисов инициализации массива C# Мне было интересно, почему C# всегда выводит массив int/Int32
где меньший тип данных, такой как byte
или же short
было бы достаточно.
new[] { 30, 130, 230 } // sbyte[] suffices but becomes int[]
new[] { -1, 125, -119 } // sbyte[] suffices but becomes int[]
new[] { -31647, -1337, 23456} // short suffices but becomes int[]
В указанном вопросе Эрик Липперт утверждает, что используется "лучший тип" - см. Ниже, но как int
самый лучший тип? Если мы идем за излишним, почему бы не использовать long
затем?
Тип элемента массива определяется путем вычисления наилучшего типа, если таковой имеется, из всех заданных элементов, имеющих типы. Все элементы должны быть неявно конвертируемыми в этот тип.
Я подозреваю, что обработка 8 или 16-битных типов данных может быть быстрее, чем 32-битных структур, например, при использовании SIMD, где четыре byte
экземпляры могут помещаться в регистровом пространстве одного int/Int32
, Я знаю, что инструкции SSE (широко) не используются компилятором JIT, но это использование ' int
везде "гарантирует, что это не очень поможет, когда JIT-компилятор собирается включить такие оптимизации.
Может ли кто-то уточнить эти факты и сказать, почему он всегда прибегает к int
?
// Редактировать // Меня не волнует спецификация, которая предписывает считать литерал без префикса int
, Перефразировать вопрос:
Почему используются типы данных, которые больше, чем нужно? Почему в спецификации есть это правило для литералов? Каковы преимущества, так как огромным недостатком является дальнейшая оптимизация (SIMD).
5 ответов
Почему используются типы данных, которые больше, чем нужно?
Количество бизнес-приложений, в которых вы выполняете вычисления в целых числах и можете гарантировать, что результат уместится в байт или шорт, исчезающе мало. Количество бизнес-приложений, в которых результат вычисления целого числа вписывается в int, огромно.
Почему в спецификации есть это правило для литералов?
Потому что это совершенно разумное правило. Это последовательно, ясно и понятно. Это делает хороший компромисс между многими языковыми целями, такими как разумная производительность, совместимость с существующим неуправляемым кодом, знакомство с пользователями других языков и обработка чисел как чисел, а не как битовых шаблонов. Подавляющее большинство программ на C# используют числа в качестве чисел.
Каковы преимущества, так как огромным недостатком является дальнейшая оптимизация (SIMD).
Уверяю вас, что ни один из тысячи программистов на C# не перечислит "трудность использования преимуществ SIMD-оптимизации" как "огромный недостаток" семантики вывода типов массива в C#. На самом деле вы можете быть единственным. Это, конечно, не произошло бы со мной. Если вы тот человек, который так заботится об этом, сделайте манифест типа в инициализаторе массива.
C# не был предназначен для извлечения каждой последней унции производительности из машин, которые могут быть изобретены в будущем, и, в частности, не был предназначен для этого, когда речь идет о выводе типов. Это было разработано, чтобы увеличить производительность разработчиков бизнес-направления, и разработчики бизнес-направления не думают о columnWidths = new [] { 10, 20, 30 };
как массив байтов.
C# 5.0 spec 2.4.4.2
• Если у литерала нет суффикса, он имеет первый из этих типов, в котором его значение может быть представлено: int, uint, long, ulong.
• Если к литералу добавляется суффикс U или u, он имеет первый из этих типов, в котором может быть представлено его значение: uint, ulong.
• Если к литералу добавляется суффикс L или l, он имеет первый из этих типов, в котором может быть представлено его значение: long, ulong.
• Если к литералу добавляется суффикс UL, Ul, uL, ul, LU, Lu, lU или lu, он относится к типу ulong.
Все ваши примеры попали первыми в этом списке... int
,
Все интегральные литералы следуют этому правилу. Вот почему var i = 10;
выводится как int
тоже.
Когда вы ставите целочисленное значение без суффикса, как 30, 130, 230
вы объявляете значение int32; так
new[] { 30, 130, 230 }; // <- array of int's
и если вам нужен массив байтов, вы должны указать его явно:
new byte[] { 30, 130, 230 }; // <- treat each value as byte
Все литералы, которые вы используете в качестве примеров, имеют System.Int32
в то время как значения могут быть сохранены без потерь в суженных целочисленных типах (например, System.Int16
) синтаксис говорит System.Int32
,
Поскольку все указанные члены каждого массива System.Int32
Массив имеет тип System.Int32[]
,
Конечно, можно определить язык, в котором целочисленные литералы (без других указаний, таких как суффиксы) имеют тип "наименьший целочисленный тип, достаточный для хранения значения", что язык не является C#.
В последней спецификации V5.0 - C# Language (из моей установки VS2013), в разделе 2.4.4.2:
Целочисленные литералы используются для записи значений типов
int
,uint
,long
, а такжеulong
,
То есть. нет возможности написать byte
, sbyte
, short
, или же unsigned short
буквально без гипсов.
Я считаю, что операции всегда будут выполняться быстрее в собственном битовом размере, поэтому int
для 32-битных машин, отсюда и соглашение.
Это также означает, что для запуска 64-битных приложений лучше использовать in t64, чем in t для массивов.