Обычное арифметическое преобразование - лучший набор правил? - PullRequest
1 голос
/ 07 мая 2009

Рассмотрим следующий код:

void f(byte x) {print("byte");}
void f(short x) {print("short");}
void f(int x) {print("int");}

void main() {
    byte b1, b2;
    short s1, s2;

    f(b1 + b2); // byte + byte = int
    f(s1 + s2); // short + short = int
}

В C ++, C #, D и Java оба вызова функций разрешают перегрузки "int" ... Я уже понимаю, это "в спецификациях", но почему языки разработаны таким образом ? Я ищу более глубокую причину.

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

byte + byte --> byte
sbyte + sbyte --> sbyte
byte + sbyte --> short
short + short --> short
ushort + ushort --> ushort
short + ushort --> int
// etc...

Это устранит неудобный код, такой как short s3 = (short)(s1 + s2), а также сделает IMO более интуитивно понятным и более простым для понимания.

Это наследие со времен C или есть более веские причины для нынешнего поведения?

Ответы [ 2 ]

2 голосов
/ 07 мая 2009

Цитируется из этого блога MSDN :

байт b = 32; байт с = 240; int i = b + с; // что я?

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

Аналогично,

int j = -b;

приведет к тому, что j будет иметь значение 224 а не -32 по той же причине.

Это действительно то, что вы хотите?

...

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

Кроме того, стоит отметить, что добавление в этих приведениях означает только дополнительный набор текста и ничего более. Как только JIT (или, возможно, сам статический компилятор) сводит арифметическую операцию к базовой инструкции процессора, ничего более умного не происходит - это просто то, обрабатывается ли число как int или byte.

Это хороший вопрос, однако ... совсем не очевидный. Надеюсь, теперь вам понятны причины.

0 голосов
/ 08 декабря 2010

Лучший набор правил ИМХО, если бы при условии, что операторы смещения могут использоваться только с постоянными значениями смещения (используйте функции смещения для переменных величин смещения), было бы то, что результаты любого арифметического выражения всегда должны оцениваться так, как если бы были обработаны с максимально возможным типом со знаком или без знака, при условии, что любой из них может быть статически гарантированно давать правильные результаты (немного хитрые правила будут применяться в случаях, когда самого большого типа со знаком может быть недостаточно). При условии, что операнды сдвига могут быть только константами, во время компиляции можно довольно легко определить, какое наибольшее значимое значение может быть у любого операнда, поэтому я не вижу веской причины для компиляторов не смотреть на то, как используется результат оператора. при принятии решения о реализации оператора.

...