байт + байт = интервал …, почему?

@try {
    // Try something
}
@catch (NSException * e) {
    NSLog(@"Exception: %@", e); 
}
@finally {
    // Added to show finally works as well
}
356
задан Raktim Biswas 29 May 2016 в 23:15
поделиться

15 ответов

Я думаю, что это дизайнерское решение о том, какая операция была более распространенной ... Если byte + byte = byte, возможно, гораздо больше людей будет беспокоить необходимость преобразования в int, когда int требуется как результат.

0
ответ дан 23 November 2019 в 00:21
поделиться

Я подозреваю, что C # на самом деле вызывает оператор + , определенный в int (который возвращает int , если вы не в a проверил блок ) и неявно приведение обоих ваших байтов / сокращает в ints . Вот почему поведение кажется непоследовательным.

4
ответ дан 23 November 2019 в 00:21
поделиться

Добавление байтов не определено. Таким образом, они приводятся к типу int для добавления. Это верно для большинства математических операций и байтов. (обратите внимание, что это было так в старых языках, я предполагаю, что это верно и сегодня).

1
ответ дан 23 November 2019 в 00:21
поделиться

Из спецификации языка C # 1.6.7.5 7.2.6.2 Бинарные числовые расширения он преобразует оба операнда в int, если он не может поместиться в несколько других категорий. Я предполагаю, что они не перегружали оператор +, чтобы он принимал байт в качестве параметра, но хотят, чтобы он работал нормально, поэтому они просто используют тип данных int.

Спецификация языка C #

5
ответ дан 23 November 2019 в 00:21
поделиться

Третья строка вашего фрагмента кода:

byte z = x + y;

на самом деле означает

byte z = (int) x + (int) y;

Итак, нет операции + над байтами, байты сначала преобразуются в целые числа и результат сложения двух целых чисел является (32-битным) целым числом.

220
ответ дан 23 November 2019 в 00:21
поделиться

Это из-за переполнения и переноса.

Если вы добавите два 8-битных числа, они могут переполниться в 9-й бит.

Пример:

  1111 1111
+ 0000 0001
-----------
1 0000 0000

Я не знаю конечно, но я предполагаю, что ints , longs и double отведено больше места, потому что они сами по себе довольно большие. Кроме того, они кратны 4, что более эффективно для компьютеров, так как ширина внутренней шины данных составляет 4 байта или 32 бита (сейчас 64 бита становятся все более распространенными). Byte и short немного менее эффективны, но они могут сэкономить место.

7
ответ дан 23 November 2019 в 00:21
поделиться

В дополнение ко всем остальным замечательным комментариям, я подумал, что добавлю один небольшой лакомый кусочек. Многие комментарии задаются вопросом, почему int, long и почти любой другой числовой тип также не следует этому правилу ... возвращать "больший" тип в ответ на arithmatic.

Многие ответы приходилось делать с производительностью (ну 32 бита быстрее 8 бит). На самом деле, 8-битное число по-прежнему является 32-битным числом для 32-битного процессора ... даже если вы добавите два байта, фрагмент данных, с которым работает процессор, будет 32-битным независимо ... поэтому добавление int не будет будь «быстрее», чем добавление двух байтов ... все равно процессору. СЕЙЧАС добавление двух целых чисел БУДЕТ быстрее, чем добавление двух длинных чисел на 32-битном процессоре, потому что добавление двух длинных чисел требует больше микроопс, поскольку вы Переработаем числа шире, чем слово процессора.

Я думаю, что основная причина того, что байтовая арифметика приводит к целым числам, довольно ясна и прямолинейна: 8-битные просто не идут очень далеко! : D С 8 битами у вас есть беззнаковый диапазон от 0 до 255. Это не много места для работы ... вероятность того, что вы столкнетесь с ограничениями по байтам, ОЧЕНЬ высока при их использовании в арифметике. Однако вероятность того, что у вас закончатся биты при работе с целыми, длинными, двойными и т. Д., Значительно ниже ... достаточно мала, чтобы мы очень редко сталкивались с потребностью в большем количестве.

Автоматическое преобразование из байта в int является логическим , потому что размер байта очень мал. Автоматическое преобразование из int в long, float в double и т. Д.

-1
ответ дан 23 November 2019 в 00:21
поделиться

Я помню, как однажды читал что-то от Джона Скита (сейчас не могу найти, буду искать) о том, как байт на самом деле не перегружает оператор +. Фактически, при добавлении двух байтов, как в вашем примере, каждый байт фактически неявно преобразуется в int. Результатом этого, очевидно, является тип int. Теперь о том, ПОЧЕМУ это было разработано таким образом, я буду ждать, пока сам Джон Скит напишет:)

РЕДАКТИРОВАТЬ: Нашел! Отличная информация по этой теме здесь .

13
ответ дан 23 November 2019 в 00:21
поделиться

Вероятно, это было практическое решение со стороны разработчиков языка. В конце концов, int - это Int32, 32-битное целое число со знаком. Всякий раз, когда вы выполняете целочисленную операцию с типом, меньшим, чем int, он в любом случае будет преобразован в 32-битный подписанный int почти любым 32-битным процессором. Это, в сочетании с вероятностью переполнения небольших целых чисел, вероятно, заключило сделку. Это избавляет вас от рутинной работы по непрерывной проверке переполнения / недостаточного потока, и когда конечный результат выражения в байтах будет в диапазоне, несмотря на то, что на некотором промежуточном этапе он будет вне диапазона, вы получите правильный результат.

Другая мысль: переполнение / недостаточный поток для этих типов должно быть смоделировано, поскольку это не произойдет естественным образом на наиболее вероятных целевых процессорах. Зачем беспокоиться?

3
ответ дан 23 November 2019 в 00:21
поделиться

Ответы, указывающие на некоторую неэффективность добавления байтов и усечения результата обратно до байта, неверны. Процессоры x86 имеют инструкции, специально разработанные для целочисленных операций с 8-битными величинами.

Фактически, для процессоров x86 / 64 выполнение 32-битных или 16-битных операций менее эффективно, чем 64-битные или 8-битные операции, из-за байта префикса операнда, который должен быть декодирован. На 32-битных машинах выполнение 16-битных операций влечет за собой такие же штрафы, но все еще существуют специальные коды операций для 8-битных операций.

Многие архитектуры RISC имеют аналогичные собственные инструкции, эффективные для слов / байтов. Те, которые обычно не имеют значения длины в битах для хранения и преобразования в знаковое значение.

Другими словами, это решение должно было быть основано на восприятии того, для чего предназначен тип байта,

26
ответ дан 23 November 2019 в 00:21
поделиться

С точки зрения «почему это вообще происходит», это потому, что в C # нет никаких операторов, определенных в C # для арифметики с байтами, sbyte, short или ushort, как говорили другие. Этот ответ касается , почему эти операторы не определены.

Я считаю, что это в основном ради производительности. Процессоры имеют встроенные операции для очень быстрой 32-битной арифметики. Выполнение обратного преобразования результата в байт автоматически может быть выполнено , но приведет к снижению производительности в том случае, если вы на самом деле не хотите этого поведения.

Я думаю ] это упоминается в одном из аннотированных стандартов C #. Глядя ...

РЕДАКТИРОВАТЬ: К сожалению, я просмотрел аннотированную спецификацию ECMA C # 2, аннотированная спецификация MS C # 3 и спецификация аннотации CLI, и ни один из них не упоминает об этом, насколько я могу видеть. Я уверен, Я видел причину, указанную выше, но меня взорвет, если я знаю где. Приносим свои извинения, фанаты ссылок: (

170
ответ дан 23 November 2019 в 00:21
поделиться

Я думал, Я видел это где-то раньше. Из этой статьи, The Old New Thing :

Предположим, мы жили в фантастическом мире. где операции с байтом привели к 'byte'.

byte b = 32;
byte c = 240;
int i = b + c; // what is i?

В этом фантастическом мире значение i будет 16! Зачем? Потому что два операнды оператора + являются байтов, поэтому сумма "b + c" вычисляется как байт, что дает 16 из-за целочисленное переполнение. (И, как я заметил ранее целочисленное переполнение - это новый вектор атаки на безопасность.)

РЕДАКТИРОВАТЬ : Раймонд защищает, по сути, подход C и C ++, использованный изначально. В комментариях он защищает тот факт, что C # использует тот же подход, исходя из обратной совместимости языка.

67
ответ дан 23 November 2019 в 00:21
поделиться

C #

ECMA-334 утверждает, что добавление разрешено только для int + int, uint + uint, long + long и ulong + ulong (ECMA-334 14.7.4). Таким образом, эти операции-кандидаты следует рассматривать в соответствии с 14.4.2. Поскольку существует неявное преобразование байта в int, uint, long и ulong, все дополнительные функции-члены являются применимыми функциональными членами в соответствии с 14.4.2.1. Мы должны найти наилучшее неявное приведение по правилам в 14.4.2.3:

Приведение(C1) к int (T1) лучше, чем приведение (C2) к uint (T2) или ulong (T2), потому что:

  • Если T1 - int, а T2 - uint или ulong, преобразование C1 является лучшим.

Приведение (C1) к int (T1) лучше, чем приведение (C2) к long (T2), потому что существует неявное приведение из int на long:

  • Если существует неявное преобразование из T1 в T2, а неявное преобразование из T2 в T1 не существует, C1 - лучшее преобразование.

Следовательно, используется функция int + int, которая возвращает int.

Это очень длинный способ сказать, что она очень глубоко похоронена в спецификации C #.

CLI

CLI работает только на 6 типах (int32, native int, int64, F, O и &). (ECMA-335, раздел 3, раздел 1.5)

Байт (int8) не является одним из этих типов и перед добавлением автоматически приводится к int32. (ECMA-335, раздел 3, раздел 1.6)

и перед добавлением автоматически приводится к int32. (ECMA-335, раздел 3, раздел 1.6)

и перед добавлением автоматически приводится к int32. (ECMA-335, раздел 3, раздел 1.6)

57
ответ дан 23 November 2019 в 00:21
поделиться

По большей части это мой ответ, относящийся к этой теме, сначала отправленный на аналогичный вопрос здесь .

Все операции с целыми числами меньше Int32 являются по умолчанию перед вычислением округляется до 32 бит. Причина, по которой результатом является Int32, заключается в том, чтобы просто оставить его как есть после расчета. Если вы проверите арифметические коды операций MSIL, единственными целочисленными типами, с которыми они работают, являются Int32 и Int64. Это «по замыслу».

Если вы желаете получить результат обратно в формате Int16, не имеет значения, выполняете ли вы приведение кода или компилятор (гипотетически) испускает преобразование «под капотом».

Например, , чтобы выполнить арифметику Int16:

short a = 2, b = 3;

short c = (short) (a + b);

Два числа будут расширяться до 32 бит, добавляться, а затем сокращаться до 16 бит, как это предполагала MS.

2
ответ дан 23 November 2019 в 00:21
поделиться

Из кода .NET Framework:

// bytes
private static object AddByte(byte Left, byte Right)
{
    short num = (short) (Left + Right);
    if (num > 0xff)
    {
        return num;
    }
    return (byte) num;
}

// shorts (int16)
private static object AddInt16(short Left, short Right)
{
    int num = Left + Right;
    if ((num <= 0x7fff) && (num >= -32768))
    {
        return (short) num;
    }
    return num;
}

Упростите с помощью .NET 3.5 и выше:

public static class Extensions 
{
    public static byte Add(this byte a, byte b)
    {
        return (byte)(a + b);
    }
}

теперь вы можете сделать:

byte a = 1, b = 2, c;
c = a.Add(b);

0
ответ дан 23 November 2019 в 00:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: