Foreversoft.ru

IT Справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Integer overflow ошибка

Integer overflow ошибка

Добрый день, уважемые мастера! У меня глупый вопрос, но тем не менее я не знаю на него ответа:
есть такие переменные:

X: DWORD;
A,B: DWORD;
и такой код:

включил Overflow checking — начал показывать ошибку, причем в том случае, если B>A, т.е. в скобках отрицательное число. X делать integer»ом нежелательно, там потом кусок на асме, он там используется как целое положительное. В чем причина, я специально ABS поставил и не помогает. Да, еще я попробовал вместо переменных написать значения, типа:

и все нормально! Почему так?


Digitman © ( 2004-06-08 10:35 ) [1]

при включенной опции проверки переполнения :

компилятор считает, что при A,B:DWORD вычисленное значение A-B так же должно иметь явный тип DWORD, в диапазон представления значений которого отиц.значения не входят, о чем в ран-тайм и сообщается исключением по integer overflow

компилятор вообще генерирует код вызова ф-ции Abs() и операции ц/ч умножения, потому что все выражение можно вычислить на этапе компиляции, получить заведомо однозначный результат = 10 и присвоить его переменной X, что не возбудит никаких исключений, благо результ.число 10 заведомо входит в диапазон представления типа DWORD, поэтому код проверки на переполнение компилятор даже не генерирует


Digitman © ( 2004-06-08 10:37 ) [2]

читать как «вообще НЕ генерирует»


Digitman © ( 2004-06-08 10:42 ) [3]


> X делать integer»ом нежелательно, там потом кусок на асме,
> он там используется как целое положительное

никаких ограничений нет : используй в асм-блоке переменную Х как хочешь — хоть как знаковое хоть как беззнаковое .

в дан.случае абсолютно индифферентно, какой тип — integer или dword — имеет переменная Х, используемая в asm-блоке, важно что размер переменной в памяти и в том и в другом случае будет одинаков


ancara ( 2004-06-08 10:46 ) [4]

Хм. Сделал все таки ради эксперимента

история та же, а вот после такого изменения:

ошибка исчезла. Вообщем проблема решена, но как — я не понял.


Anatoly Podgoretsky © ( 2004-06-08 10:47 ) [5]

Abs бессмысленен для dword


pasha_golub © ( 2004-06-08 10:48 ) [6]

ancara (08.06.04 10:46) [4]
Проблема не решена, ИМХО, а завуалирована. Перечитайте посты Digitman © очень внимательно, иначе рискуете отгребсти по самые мама не горюй.


Digitman © ( 2004-06-08 10:52 ) [7]

и это тоже объяснимо


> Вообщем проблема решена, но как — я не понял

странно ты подходишь к решению проблемы — методом «научного тыка» ..

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

да и с опцией overflow checking — тоже ситуация сомнительная, ибо в асм-блоке, где ты волен творить с любой переменной любого типа все что угодно, компилятор бессилен отслеживать твои логические ошибки


ancara ( 2004-06-08 10:57 ) [8]

X: byte;
A: WORD;
B: DWORD;

ошибок нет! а если без Abs() то Range check error.
(в момент отладки A=7; B=8;)


ancara ( 2004-06-08 10:58 ) [9]

X: byte;
A: WORD;
B: DWORD;

Читать еще:  Smtp ошибка 550 невозможно установить отправителя

ошибок нет! а если без Abs() то Range check error.
(в момент отладки A=7; B=8;)
Дело в разрядности переменных чтоли? (16 bit, 32 bit)?


ancara ( 2004-06-08 11:09 ) [10]


> Digitman © (08.06.04 10:52) [7]

Я поясню: overflow checking я включаю время от времени (иногда всегда включен) чтобы компилятор указал на разные «слабые места», привычка у меня такая, я не только для асма ее включил.
А насчет беззнаковых — прога ориентирована на графику,
A — это ширина картинки в байтах расчетная(кол-во точек умножить на кол-во бай на точку),
B — это ширина в байтах истинная, с выравниванием (bmp-файлы должны же быть «word aligned»);
X — это величина «добавки», т.е. сколько байт нужно добавить в конец каждой строки, чтобы выравнять по словам, она не может быть меньше нуля теоретически,( но в проге почему-то может и я буду это устранять. )
именно поэтому я выбрал изначально DWORD.


Digitman © ( 2004-06-08 11:15 ) [11]


> Дело в разрядности переменных чтоли? (16 bit, 32 bit)?

в случае A-B компилятор считает результирующим типом значения выражения тип dword, иначе — integer

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


ancara ( 2004-06-08 11:43 ) [12]


> не так уж и трудно посмотреть в режиме отладки, какой маш.код
> компилятор генерирует

Вы совершенно правы :), в регистре EAX вместо 00000001 получается FFFFFFFE, а потом это рассмартивается как BYTE — маразм!
Спасибо за ценные советы.


Digitman © ( 2004-06-08 11:53 ) [13]

X := (Max(A,B) — Min(A,B)) * 2

и всех делов) .. и никаких переполнений) ..
разница между макс. и мин. значениями всегда будет >= 0


evvcom © ( 2004-06-08 14:42 ) [14]


> A — это ширина картинки в байтах расчетная(кол-во точек
> умножить на кол-во бай на точку),
> B — это ширина в байтах истинная, с выравниванием (bmp-файлы
> должны же быть «word aligned»);
> X — это величина «добавки», т.е. сколько байт нужно добавить
> в конец каждой строки, чтобы выравнять по словам, она не
> может быть меньше нуля теоретически

Из этого следует, что A, B и X можно описать как Integer и использовать X:= Abs(A-B)*2; как в вопросе. Ну а если принципиально они должны быть DWORD, то можно использовать явное приведение типов X:= Abs(Integer(A)-B)*2;
Посмотрев на код, сгенерированный компилятором, будет видно, что, возможно, потребуется еще где-нибудь применить явное приведение типов.

Почему unsigned integer overflow определяет поведение, а signed integer overflow-нет?

переполнение целого числа без знака хорошо определяется стандартами C и c++. Например,стандарт C99 ( §6.2.5/9 ) государств

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

однако, как стандарты утверждают, что переполнение целого числа со знаком является неопределенным поведением. Опять же, из стандарта C99 ( §3.4.3/1 )

примером неопределенного поведения является поведение при переполнении целого числа

есть ли исторический или (еще лучше!) техническая причина этого несоответствия?

Читать еще:  Ошибка при вызове метода контекста saveas

5 ответов

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

на практике, это только представления для значений, которые могут отличаться в зависимости от реализации: дополнения, дополнения two, знак-величина. Для беззнакового типа нет причин для стандарта разрешать изменение, потому что существует только одно очевидное двоичное представление (стандарт разрешает только двоичное представление).

C99 6.2.6.1: 3:

значения, хранящиеся в беззнаковых битовых полях и объектах типа unsigned char, должны быть представлены с использованием чистой двоичной нотации.

C99 6.2.6.2:2:

Если знак один бит, значение должно быть изменено одним из следующих способов:

— соответствующее значение со знаком бит 0 отрицательная (знак и величину);

— бит знака имеет значение — (2 N ) (два);

— бит знака имеет значение — (2 N — 1) (один дополнит).

В настоящее время все процессоры используют представление дополнения two, но подписанное арифметическое переполнение остается неопределенным, и создатели компилятора хотят, чтобы оно оставалось неопределенным, потому что они используют эту неопределенность, чтобы помочь с оптимизацией. Например этот блоге Ян Лэнс Тейлор или это жалоба Агнер Фог, и ответы на его сообщение об ошибке.

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

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

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

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

Читать еще:  Цикл с предусловием паскаль

прежде всего, обратите внимание, что C11 3.4.3, как и все примеры и примечания для ног, не является нормативным текстом и поэтому не имеет отношения к цитированию!

соответствующий текст, который утверждает, что переполнение целых чисел и поплавков является неопределенным поведением, таков:

C11 6.5 / 5

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

разъяснение относительно поведения целых типов без знака, в частности, можно найти здесь:

C11 6.2.5 / 9

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

Это делает целочисленные типы без знака частным случаем.

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

C11 6.3.1.3

6.3.1.3 целые числа со знаком и без знака

, когда значение целого числа type преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.

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

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

возможно, еще одна причина определения арифметики без знака заключается в том, что беззнаковые числа образуют целые числа по модулю 2^n, где n-ширина беззнакового числа. Неподписанные числа — это просто целые числа, представленные двоичными цифрами вместо десятичных. Выполнение стандартных операций в модульной системе хорошо изучено.

цитата OP ссылается на этот факт, но также подчеркивает тот факт, что существует только один, однозначный, логический способ представления без знака целые числа в двоичном коде. Напротив, подписанные номера чаще всего представлены с использованием дополнения two, но возможны и другие варианты, как описано в стандарте (раздел 6.2.6.2).

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

Ссылка на основную публикацию
Adblock
detector