NaN обрабатывается по-разному в разных версиях g ++ - PullRequest
2 голосов
/ 06 июля 2011

Рассмотрим следующую программу, которая явно глючит:

#include <cstdio>

double test(int n) {
    if (n % 2 == 0)
        return 0.0;
    // warning: control reaches end of non-void function
}

int main() {
    printf("%.9lf\n", test(0));
    printf("%.9lf\n", test(1));
    printf("%.9lf\n", test(2));
    printf("%.9lf\n", test(3));
    return 0;
}

При компиляции с g ++ версии 4.2.4 (Ubuntu 4.2.4-1ubuntu4) в 32-разрядной версии Ubuntu 8.04 выдает следующий вывод:

0.000000000
nan
0.000000000
nan

При компиляции с g ++ версии 4.4.3 (Ubuntu 4.4.3-4ubuntu5) на 64-битной Ubuntu 10.04 выдает следующий вывод:

0.000000000
0.000000000
0.000000000
0.000000000

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

РЕДАКТИРОВАТЬ: Извините, что не упомянул неопределенное поведение ранее. Я знаю, что разница заключается в том, что эта программа имеет неопределенное поведение. Что я хотел бы знать , почему предыдущая версия gcc, кажется, прилагает некоторые усилия и создает код, который последовательно возвращает NaN и , когда это поведение изменилось на то, которое наблюдалось в последней версии gcc , Кроме того, под «предсказуемым» я подразумевал не то, как писать хорошие программы на C ++, а то, как управлять этим поведением gcc (возможно, с некоторыми параметрами командной строки?).

Ответы [ 4 ]

12 голосов
/ 06 июля 2011

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

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

РЕДАКТИРОВАТЬ: Я утверждаю, что вы не должны полагаться на то, что компилятор , кажется, делает.

Даже если вы думаете, что должныВы не должны.

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

Единственное разумное решение здесь - это скомпилировать с -Wall и исправить те «не все возвращаемые пути возвращают значение», так что поведение 1) определено, 2) определено как you .

2 голосов
/ 06 июля 2011

Ваша функция возвращает double, но когда n % 2 != 0 ничего не возвращает.

Вы находитесь в стране неопределенного поведения.

1 голос
/ 07 июля 2011

Что я хотел бы знать, почему предыдущая версия gcc, похоже, прилагает определенные усилия и создает код, который последовательно возвращает NaN, и когда это поведение изменилось на то, которое наблюдалось в последней версии gcc.Кроме того, под «предсказуемым» я подразумевал не то, как писать хорошие программы на C ++, а то, как управлять этим поведением gcc (возможно, с некоторыми параметрами командной строки?).

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

0 голосов
/ 06 июля 2011

Игнорировать предупреждения на свой страх и риск.

if (n % 2 == 0) return 0.0; else return 0.0;

Работает правильно, иначе в половине случаев test() возвращает мусор.

И неопределенное поведение не зависит от версии, так как я получаю NaNтакже:

$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
$ uname -a
Linux tallguy 2.6.38-8-generic #42-Ubuntu SMP Mon Apr 11 03:31:50 UTC 2011 i686 i686 i386 GNU/Linux
...