Этим занимаюсь на работе. Уже автоматически if и TraceLog() вставляю (т.к. тестеры заколустали). ЗЫ. В "своём продукте" if-ов поменьше.
При неправильном выборе типов на этапе проектирования и потенциальной опасности переполнения этих типов могут возникнуть проблемы гораздо серьезнее. Например, переполнение в базе данных, с которой работаешь. Или в сторонней библиотеке. Поэтому, имхо, нет смысла автоматизировать отлов переполнения переменной в своей программе и расслабляться на этом. Необходимо правильно спроектировать и тем самым исключить возможность переполнения где либо. [Добавлено] В Си++ есть прекрасная возможность создавать свои типы данных, определять для них операторы и создавать исключения. Называется классы =) Что мешает создать свой целочисленный тип данных, который как в делфе будет ругаться при переполнении?
Как спроектировать чтобы защититься от ошибки IntO скажем в d3d10.lib? конечно еслибы у нас был компилятор...
МПМ а эта группа команд с ними в основном и работает. просто Си должен будет адаптироваться к своему процессору. на некоторых эти команды есть, там код будет линеен, а где-то придется сгенерировать прыжок, который срабатывает всегда, кроме случая с переполнением. я знаю как минимум 6 серий микроконтроллеров, где придется изрядно покрутиться (там в арифметических операциях вообще acc только может участвовать, я не говорю уже про работу с флагами переполнения и переноса). т.е. придется покрутиться Код (Text): add acc, rXXX // 1 XXX - любой номер 0-7, где-то 15 jlc #0x2 // 2 короткий прыжок через ljp в некоторых микроконтроллерах нет обратной команды и придется выкручиваться, а где есть, будет все как на x86 ljmp #0x6 // 2 короткий прыжок через код обработки переполнения <==прыгаем сюда после jlc rmv rXXX, acc // 1 XXX - любой номер 0-7, где-то 15 cmv acc, #0x1 //3 1 байт инструкция и 2 байта константа (инструкция загрузки константы а аккумулятор) rmv rXXX, acc // 1 загрузка в банк регистров аккумулятора rmv acc, rXXX // 1 восстановление из банка регистров аккумулятора <==прыгаем сюда после ljmp вместо команд перемещения могут стоять команды сохранения в стек, но у некоторых микроконтроллеров банки регистров могут быть спроецированы в начало стека, а стек растет в сторону увеличения адреса. т.е. команды положить в стек и взять из стека конфликтуют с текущим банком регистров. компилятор за этим обычно не следит и старается использовать текущий банк регистров как стек. под банком регистров здесь понимается набор регистров rXXX, который может переключаться записью номера в определенный порт или регистр управления. как правило банк регистров и сравнительно не большой стек спроецированы на общую относительно не большую, для упрощения структуры, память. это сделано для упрощения вызова подпрограмм. вызвав подпрограмму вы переключаете банк регистров и тем самым можете работать не опасаясь за их значения в программе на уровне выше. сейчас еще довольно часто могут использоваться старые модели микропроцессоров вместо микроконтроллеров. это удобно т.к. они командно-совместимы с современными процессорами. но очень большое количество команд появилось в старших моделях процессоров. я не говорю про расширения. к примеру команда salc появилась только в процессоре 80286, а чтобы его использовать как микроконтроллер нужно прикрепить его не очень маленькую обвязку и по этим причинам (нет места на схеме) предпочтения отдают относительно (него) простым более ранним моделям (к примеру весьма популярны 8086/8088). а в этих моделях просто нет большого количества команд. для 8086/8088 код коррекции переполнения будет примерно такой Код (Text): add ax, cx adc dx, 0 //но тогда результат контроля будет в регистре dx и за ним тоже придется следить //поэтому скорее всего будет что-то типа этого add ax, cx jnc @f //тут код контроля переполнения //но минус в том, что постоянно выполняется jnc, кроме случаев переполнения, и это сильно замедляет код на и так медленных микропроцессорах @@: это лишь маленькая дискуссия по поводу большой проблемы. на самом деле это требует очень большого количества кода и то что делфи включает такой код в приложение это лишь для безопасности. а в принципе я могу с вами согласиться. почему нет такой возможности у компилятора Си. именно возможности. многие программисты попросту не видят в этом большой проблемы и думают что все будет в порядке, только возьми по больше памяти под переменную. но такая возможность быть должна и ее не обязательно включать по умолчанию (а не писать зачем-то свой код еще больше замедляющий целочисленные вычисления). в хорошей среде все предусмотрено за нас и реализовано там, где должно быть реализовано, а не возложено на пользователей. иначе говоря, раз в процессоре эта возможность есть, то почему компилятор не предоставляет интерфейс для ее использования, а говорит пишите сами. это отнюдь не для хорошей жизни. сами по судите. типы данных придуманы не от хорошей жизни, а если столько примитивные типы данных создавать на уровне классов, то для реализации сложения потребуется очень много времени и переносимости тут может не оказаться Код (Text): mov eax, [esi] mov edx, [ebp] //inline add eax, edx //c=a.data+b.data cmp eax, [esi] //if (c<a.data) jae @f ... какие-то действия по контролю за переполнением @@: и это если компилятору удастся создать inline код, а если нет Код (Text): push ebp push esi call [class.add] в то время как процессор и без этих загромождений спокойно определяет переполнение или перенос.
Спасибо за ответ! просветился немного. Вот например ведь скорее всего компиляторы расчитанные на те мк на которых С возможен, будут иметь ключи(давно мк трогал, помню слабо) для явного указания типа устройства. Те при наличии исходника нужно будет только пересобрать. Или на мк тоже важно чтобы прошивки работали слепо без пересборки, типа куда вшили там и живи? Насколько помню там всёже слишком много разниц чтобы так слепо действовать. И вообще там сплошь ассемблер. В котором проблема дырявых абстракций отсутствует напрочь. Те вобщем непонятно... Ну и ладно малыши, на них обезьяны не програмируют. Там нет 128мб озу под стек и созданных в нем потомков абстрактных бесов. Но микрософт, интел с++... непонятно... Что больше всего смущает, отсутствие упоминаний об это в литературе... Чуствую есть какоето простое и логическое объяснение. но не вижу его.
Почемубы не заслушать мнение специалиста с мировым именем. На арене цирка дрессировщик пингвинов, финский Куклачов крайнего севера, Линус Торвальдс. From torvalds@penguin.transmeta.com Tue Feb 6 09:36:41 2001 From: torvalds@penguin.transmeta.com (Linus Torvalds) Newsgroups: comp.os.linux.development.apps Subject: Re: Overflow detection in gcc-produced code? In article <slrn97tsgd.pu3.BobT@linus.cs.queensu.ca>, Bob Tennent <rdtennent@hotmail.com> wrote: >Is there any way to detect that an overflow has occurred in x86 integer >arithmetic code produced by gcc? unsigned long x, y, sum; int overflow = 0; sum = x+y; if (sum < x) overflow = 1; Works portably in C (but only with "unsigned" types that are guaranteed to have twos-complement behaviour and well-defined overflow semantics). And good compilers will notice that "overflow" is really just the carry flag, and optimize it. I don't remember if gcc counts as "good" in this case, but I doubt it For signed integer arithmetic, you're basically screwed. A compiler is in theory allowed to do anything at all for signed overflows, so you cannot portably test the result at all: you have to detect the overflow before the operation happens. In practice, of course, all x86 compilers will just result in the "proper" overflow value, but you still have to test whether an overflow occurred. At some point it probably becomes easier to do it with inline asm. Especially if it needs to be efficient. One (inefficient) way might be to do the calculation in "long long" and do a long long x, y, sum; in toverflow = 0; sum = x + y; if (sum != (long)sum) overflow = 1; but if you look at the actual code it generates, you'll be really sad. Linus