Ошибка переполнения переменной.

диапазоны не нужны. типичный паскалевский атавизм

3 лайка

Мне тут знающие люди из MS рассказали, что в .NET можно включить контроль переполнения целых. Как-то так:

dotnet run /p:CheckForOverflowUnderflow=true

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

Вы говорите о создании аналога checked/unchecked из C#?

Да, вижу:

Операция add.ovf

Это надо все операции с целыми генерировать альтернативные.

Ну, немаленькая работа. Интересная - согласен.

Не могу оценить пока целесообразность. В частности, насколько медленнее будет выполняться. И в каких сценариях это можно использовать.

1 лайк

Видимо, да.

Сценарии более чем очевидны: применение в обучении. Согласитесь, это немалая доля использования вашего прекрасного продукта.

Да и вообще: чего стоят все разговоры о безопасности, контроле типов и пр., если переполнение не контролируется.

1 лайк

Переполнение должно контролироваться аппаратно, т.е. вызывать аппаратное прерывание, которое может быть затем обработано операционной системой. В противном случае такой контроль драматически снижает производительность. Это было известно еще со времен ЭВМ второго поколения. Самая массовая серия ЭВМ третьего поколения IBM\360 - 370 и их советские клоны EC ЭВМ - располагала процессором, в котором была аппаратно реализована целочисленная арифметика, арифметика с плавающей точной и десятичная арифметика. Так вот: этот процессор не имел аппаратных прерываний для целочисленной арифметики. То же самое с процессорами современных “персоналок”, будь они от Intel, AMD или Apple. То же практически со всеми специализированными процессорами.

Причина отсутствия аппаратного прерывания процессора для целочисленной арифметики кроется в том, что оно бесполезно. Существует лишь одна общая инструкция загрузки некоторого количества байт в регистры процессора и он “не понимает”, это число со знаком или беззнаковое - это лишь интерпретация программиста. А поскольку переполнение связано с неверной установкой именно знакового разряда, делать аппаратное прерывание означает на деле получить массу ложных его возникновений.

Посему Ваше эмоциональное высказывание - это так, выхлоп в Космос.

А вот это я не понял. Разве проверка переполнения реализуется не как то так (но, разумеется, на аппаратном уровне):

function Add_Ovf(a,b: integer): integer;
begin
  Result := a+b;
  if Result < a then
    raise new System.OverflowException;
end;

И где тут

Вы действительно не поняли. На аппаратном уровне проверка переполнения в целочисленной арифметике вообще не реализована, о чем я столько времени старательно пытался написать. И вот почему.

Целое без знака - это машинное слово длиной в регистр процессора. Например, 32 бита.

Пусть в регистре находится значение 0xFFFFFFFF = 11111111 11111111 11111111 11111111

Если его интерпретировать, как Unsigned integer (32-bit), это будет десятичное число 4294967295, а если как Signed integer (32-bit) - это будет десятичое число -1.

Загрузим в регистр значение 0x7FFFFFFF = 01111111 11111111 11111111 11111111

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

Загрузим в другой регистр значение 0x00000001 = 00000000 00000000 00000000 00000001

А теперь попросим процессор сложить содержимое этих регистров, как целые числа.

   0x7FFFFFFF = 01111111 11111111 11111111 11111111
+  0x00000001 = 00000000 00000000 00000000 00000001
=  0x80000000 = 10000000 00000000 00000000 00000000

А теперь вопрос - это было переполнение при сложении двух целых чисел со знаком (и по нему надо делать прерывание) или нормальное сложение двух беззнаковых 32-битных целых (и по нему прерывание делать не надо) ?

Этого процессор не знает, потому что у него нет двух разных операций сложения.

Напоследок - еще один “убойный” момент. Современные процессоры персоналок - 64-битные. И регистры у них такие же. Когда мы складываем числа длиной 1, 2 или 4 байта, сами догадаетесь, какие биты считаются знаковыми?

3 лайка

Если уже добавлять инструкции для сложения с контролем переполнения - какая разница сколько их добавить? Тех же операторов сравнения (> и <) для каждого размера и знаковости сделали же.

И получать их вызов из .Net кода было бы вполне возможно, 1 из основных применений CIL как промежуточного языка - как раз чтоб оптимизировать под определённый процессор при запуске.

Дерзайте ныне ободренны
Раченьем вашим показать,
Что может собственных Платонов
И быстрых разумом Невтонов
Российская земля рождать.
          М.В. Ломоносов

Инструкцию к процессору добавить невозможно. Можно лишь добавлять программно эмулируемые операции, но платой за это будет огромная неэффективность. И главный вопрос: а многим ли и как часто это нужно? Неужели компании и отдельные люди с мировым признанием на самом деле настолько дебильны, что не догадались за сорок лет ввести в создаваемые аппаратные и программные платформы прерывания по арифметическому переполнению целых чисел?

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

Разумеется, я говорил про добавление инструкции на этапе создания новой модели процессора.

И - вы пока только 1 раз вскользь сказали что не видели процессоры в которых эта инструкция реализована (а как много вы проверили?) и теперь говорите в стиле “нету - наверное значит есть причина”, что не даёт никакой полезной информации и может использоваться только для убийства дискуссии.

Т.е. ради сомнительного “новшества” Вы предлагаете разработать процессор, который будет иметь расширенную систему команд, отличную от ныне распространенных процессоров, что потребует проектных разработок, аппаратная реализация несомненно удорожит такой процессор (вспомните и сравните стоимость процессоров CISC и RISC). А потом еще и разработчики ПО должны будут озадачиться выпуском отдельного софта, позволяющего работать с этими новыми командами, т.е. поддерживать дополнительные семейства процессоров. И снова повторю - ради чего? Ублажить небольшую группку людей, которые не в состоянии определить возможность возникновения переполнения в операциях с индексами и счетчиками? Поскольку для иных целей целочисленная арифметика используется крайне редко.

Ну если для Вас IBM\360-370-380, Intel, AMD и Apple не показательны, уж и не знаю… Найдите в литературе, что ли, ссылки на процессоры, которые имеют возможность выдавать аппаратные прерывания по переполнению в операциях с целочисленными операндами разного типа.

И опять Вы неправы: причину я указал. Пожалуйста, научитесь наконец внимательно читать написанное, если хотите возражать по существу.

Я ничего не предлагаю. checked это защита от дурака, и не особо полезная.

Но я не согласен только с тем что вы назвали изначальной проблемой. Да и производительность тоже, всё же в наше время повседневных задачах производительность это не так важно как безопастность. И наличие таких инструкций не замедлило бы скорость выполнения задач где производительность важна. Поэтому это не настолько уж и нереально.

Я не посчитал это за 100% достоверную информацию, потому что Intel, AMD и Apple делают множество разных процессоров. Даже если у большинства их процессоров нету таких инструкций - не значит что у всех нету. И - вы ведь тоже не проверили все модели процессоров? Если что - я, опять же, не предлагаю это делать)).

У меня нет привычки прыгать через части сообщений. Я говорил про конкретную часть вашего сообщения, про то что она не о чём.

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

В современных ЯП слишком много сахара. От этого многим становится приторно.

Иногда и самому нужно думать.

Ввести в язык можно всё что угодно, но стоит ли оно того? (вопрос риторический)

Касательно ввода checked/unchecked в язык. Перед добавлением нового средства в язык всегда стоит отвечать на вопрос (это я говорю @c3c): Насколько это будет востребовано? Стоит помнить, что при ответе следует учитывать целевую аудиторию PascalABC.NET. Нет, я не отговариваю и не призываю разработчиков вводить данную конструкцию в язык, я лишь обращаю внимание @c3c на данные вопросы.

Лично моё мнение таково: если бы PascalABC.NET был признан официально языком для промышленной разработки, то в таком случае вероятность ввода вышеуказанной конструкции была бы больше. Её отсутствие в языке мне не мешает.

1 лайк

Да, согласен. Вот как раз сейчас я рассказываю в лекциях студентам первого курса про целочисленное переполнение. Эта возможность была бы нельзя как кстати.

Производительность потестирую чуть позже - неизвестно, в какие машинные коды это затем переводится. Но даже при проседании производительности это можно было бы использовать например в Debug-режиме для контроля за некоторыми ошибками. А потом в Release-режиме можно было бы запускать программы более безопасно.

Я даже знаю, куда это можно было вставить в моём курсе. Когда мне предлагают алгоритм перемены местами двух целых значений вида

a := a + b;
b := a - b;
a := a - b;

я бы мог предложить запустить этот код в режиме check overflow

Так что идея бесспорно хорошая.

Отдельное спасибо, что Вы породили тут на форуме такое бурное обсуждение :wink:

2 лайка

Очень рад, что Вы это принимаете. За бурление можно не благодарить, оно возникает помимо моих усилий :wink:

Ну, и чтоб два раза не вставать:

> program TenPow13;
> var
>    x, i: integer;
> begin
>    println(maxint);
>    x := 10;
>    i := x*sqr(sqr(x*sqr(x)));
>    println(i, x*sqr(sqr(x*sqr(x))));
> end.   

И вывод:

> 2147483647 
> 1316134912 10000000000000

Если это будет только в отладочном режиме, да и то опционально - ради бога, пусть будет. ))) В конце-концов обсуждение - оно не для того, чтобы пытаться кого-либопринудить, а лишь показать разные аспекты явления.

1 лайк