Отлов переполнения при выполнении арифметических операций

Здравствуйте.

Хочу отловить переполнение при выполнени арифметических операций. Например, есть переменная x = 0xFF-2 типа unsigned char. Если мы прибавим к ней 1, переполнения не возникнет, но если прибавим 3, то возникнет переполнение и значение x станет равно 0.

Единственное, что я придумал, это проверять значение флага процессора cf и написал вот такой код:

#include <iostream>

//Функция возвращает состояние флага процессора cf, который указывает на переполнение
//Работает только для процессоров intel
bool get_cf() 
{
    bool flag;
    asm volatile( "jnc no\n\t"           //Если флаг не установлен, переходим к метке no 
         "movb $1, %0\n\t"               //Если флаг установлен, записываем 1 в %0
         "jmp end_proc\n\t"              //Завершаем работу вставки
         "no: movb $0, %0\n"             //Операнд %0 = 0, что значит что флаг не установлен
         "end_proc:\n\t"
         : "=m"( flag )                  //Выходной операнд flag, находится в памяти
         :                      //Нет входных операндов
         :                      //Нет изменяемых регистров
         );
    return flag;
}

int main()
{
    unsigned char x = 0xFF-2;
    bool flag;

    x + 1; //Переполнения не должно возникнуть...
    flag = get_cf();
    std::cout << flag << std::endl; //...поэтому вывод должен быть "0"

    x + 3; //Должно возникнуть переполнение...
    flag = get_cf();
    std::cout << flag << std::endl; //...поэтому вывод должен быть "1"

    return 0;
}

Но есть две проблемы:

  1. Как я понимаю, это не кросссплатформенный способ проверки. Этот способ работает только для процессоров intel, а мне хочется кроссплатформенный способ.
  2. Даже этот код не работает. Он выводит «0 0» вместо «0 1» ожидаемых. Вину возлагал на оптимизацию, но её полное отключение не помогло.

Как быть?

Я тут пораскинул мозгами и придумал: а что если в этом виноват return flag из get_cf? По идее, return это pushl код возврата, а в инструкцию pushl входит %esp + 4, то есть арифметическая операция, где переполнения не возникает. Может в этом дело?

Действительно, решение, как всегда лежало на поверхности :\

P.S.: А разве не наоборот? Должно же быть:

if (i++ < i) {
   // переполнение произошло
}

Нет, т.к. оператор постинкремента возвращает значение переменной до выполнения инкремента. А значение i в правой части сравнения уже будет увеличенным на единицу. Т.е. порядок операндов в данном случае важен :)

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

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

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.