Почему эта ошибка деления на ноль возникает только в оптимизированном коде? - PullRequest
3 голосов
/ 04 октября 2010

Я только что нашел ошибку, которая, как ни странно, возникала только при включенной оптимизации (g++ -O2).Это был Arithmetic exception в следующем коде, когда interval был установлен на ноль (из аргумента командной строки):

for(int i = 0; i < n; ++i) {
  if((i + 1) % interval == 0) { // exception here
    DoSomething();
  }
}

Очевидно, что операция с нулевым модулем вызвала исключение деления на ноль, но почему это произошло только тогда, когда код был скомпилирован с включенной оптимизацией?

Ответы [ 4 ]

13 голосов
/ 04 октября 2010

Деление на ноль всегда неопределенное поведение. Тот факт, что вы получаете разные результаты с разными настройками оптимизации, все еще вписывается в определение неопределенного поведения.

1 голос
/ 04 октября 2010

Свертывание констант.

Вы объявили интервал как глобальное const int, и компилятор взял ваше слово.

0 голосов
/ 04 октября 2010

Можете ли вы привести пример, демонстрирующий проблему?Если оптимизация меняет результаты, вам нужно разобрать код и сравнить разницу.Какая у вас целевая платформа?х86, рука, ппц?операционная система?etc?

#include 
const int interval=BOB;
int main ( void )
{
    int i,n;
    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % interval == 0)
        { // exception here
            printf("%d\n",i);
        }
    }
    return(0);
}
gcc interval.c -DBOB=0 -O2 -o interval
interval.c: In function ‘main’:
interval.c:15: warning: division by zero

Компилятор понял это ...

РЕДАКТИРОВАТЬ:

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

#include <stdio.h>
const int interval;
int main ( int argc, char *argv[] )
{
    int i,n;
    if(argc<2) return(1);
    interval=atoi(argv[1]);

    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % interval == 0)
        { // exception here
            printf("%d\n",i);
        }
    }
    return(0);
}
gcc -o interval interval.c
interval.c: In function ‘main’:
interval.c:7: error: assignment of read-only variable ‘interval’

Пожалуйста, предоставьте полный пример.

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

РЕДАКТИРОВАТЬ:

#include <stdio.h>
int main ( int argc, char *argv[] )
{
const int interval;
    int i,n;
    if(argc<2) return(1);
    interval=atoi(argv[1]);

    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % interval == 0)
        { // exception here
            printf("%d\n",i);
        }
    }
    return(0);
}

gcc -c interval.c 
interval.c: In function ‘main’:
interval.c:7: error: assignment of read-only variable ‘interval’

Компилятор все еще знает, что это переменная только для чтения, используя адрес для указания неконстантной переменной, он не меняет своего состояния только для чтения, просто избавляется от ошибки компилятора и по-прежнему дает сбой в долгосрочной перспективе.Как и предполагалось, если, например, .text помещается в постоянную память (rom / flash), то независимо от того, сколько игр с адресацией и указателями вы играете, вы не сможете изменить время выполнения, пока вы не удалите const и не сделаете его доступным для чтения /написать переменную.Подобные манипуляции с указателями в любом случае являются кардинальным грехом, потому что они могут и в конечном итоге потерпят неудачу, если / когда вы оптимизируете (если вы используете действительно хороший компилятор и не обязательно gcc, хотя он и не работает на gcc) (99.999999999999% времениудача в том, что это работает, но очень объяснимо, когда оно терпит неудачу и указывает на дизайн программного обеспечения, а не на компилятор или язык).Если const не является основной причиной этого вопроса, просто удалите const и приведите нам полный пример, демонстрирующий проблему.В течение дня или дня это может быть закрыто.

РЕДАКТИРОВАТЬ 2:

unsigned int fun  ( unsigned int a )
{
    const unsigned int b = 7;
    *(unsigned int *)&b = 5;
    return(a+b);
}

скомпилируйте выше с оптимизацией, и вы получите:

    .global fun
fun:
    add r0, r0, #7
    bx  lr

, как и ожидалось,const делает b только для чтения.без const:

unsigned int fun  ( unsigned int a )
{
    unsigned int b = 7;
    *(unsigned int *)&b = 5;
    return(a+b);
}
    .global fun
fun:
    add r0, r0, #5
    bx  lr

Что меня удивляет, но тем не менее демонстрирует, как работает const.

0 голосов
/ 04 октября 2010

Вы не показываете нам, где установлен «интервал». Оптимизатор может делать что-то, что устанавливает 'interval' в 0. Измените ваш код на

for(int i = 0; i < n; ++i) {
  if (0==interval) { break; }
  if((i + 1) % interval == 0) { // exception here
    DoSomething();
  }
}

И посмотри, все ли получишь ошибку. Или, еще лучше, покажите нам, где «интервал» получает свое значение.

...