2009-05-07 5 views
1

Рассмотрим следующий код:Обычное арифметическое преобразование - лучший набор правил?

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, как функция вызывает решимость к «ИНТ» перегрузках ... я уже реализовать это «в спецификации», но почему языки разработаны таким образом? Я ищу более глубокую причину.

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

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

Это позволит устранить неудобного код, такой как short s3 = (short)(s1 + s2), так как так как ИМО гораздо интуитивнее и понятнее.

Это оставшееся наследие со дней C, или есть ли лучшие причины для текущего поведения?

+0

Отмечу, что любая программа с "void main()" не определена стандартами C и C++, и у вас нет причин жаловаться на все, что она делает. Используйте «int main()», если вы собираетесь обсуждать стандартизованное поведение. –

+0

Я упомянул другие языки, кроме C и C++. Подумайте, что это просто псевдокод и ничего больше. После небольших изменений (таких как изменение void на int и байт на char, а также печать на printf и т. Д.), Он будет компилироваться на любом C-подобном языке и демонстрирует поведение, которое я описал. Неужели вы не ожидали, что тот же неизменный исходный файл будет компилироваться на всех упомянутых языках, не так ли? – zildjohn01

ответ

2

Цитируется this MSDN blog post:

байт B = 32; байт c = 240; int i = b + c; // что такое i?

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

Аналогично,

Int J = -b;

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

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

...

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

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

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

+1

Возвращаясь к этому через год ... Я нахожу, что я больше резонирую с комментариями к этой статье, чем сама статья. Ну, по крайней мере, я понимаю дизайнерское решение. – zildjohn01

+0

Как насчет наличия разных типов «обертывания» и без обертывания целых чисел, с правилом, которое типы упаковки не могут быть конвертированы в любые другие числовые типы, но имеют функцию или свойство для сообщения либо наименьшего неотрицательного числа, которое при добавлении к нулю, даст заданное значение, или же значение наименьшей величины, которое при добавлении к нулю даст заданное значение. Тогда '(240wb + 255wb) .AsUnsigned' даст номер 239, а' (240wb + 255wb) .AsSigned' будет давать номер -17. Я думаю, что все случаи, которые компилируются, дадут ясное ожидаемое поведение. – supercat

0

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

 Смежные вопросы

  • Нет связанных вопросов^_^