0/0 в C - gcc-7 или выше - PullRequest
       1

0/0 в C - gcc-7 или выше

0 голосов
/ 30 апреля 2019

Математически, 0 / 0 не определено. Но в программировании на C (особенно gcc компилятор gcc-7.3.0 в Ubuntu) он выдает ответ как 1. Я хотел бы знать причину. Это работает путем повторного вычитания? Для того же кода, если я использую n = 1 / n, я получаю исключение с плавающей запятой. Однако для gcc-5.3.0 выдает ошибку.

#include <stdio.h>

int main() {
    int n = 5;
    n = n - 5;
    switch (n) {
    case 0:
        printf("n= %d", n);
        n = n / n;
        printf("n calc= %d", n);
        break;
    case 5:
        printf("n=5");
        break;
    default:
        printf("n=1");
        break;
    }
    return 0;
}

Ответы [ 3 ]

4 голосов
/ 30 апреля 2019

Деление на ноль - неопределенное поведение в C-программировании (C11 6.5.5 §6).Это означает, что нет предсказуемого результата, невозможно сказать, что может сделать ваша программа.

Бессмысленно пытаться объяснить, почему вы получаете один конкретный результат «что-то может произойти».Это может напечатать 1, это может напечатать 42, это может напечатать вообще ничего.Программа может аварийно завершить работу и сгореть.Если вы запустите программу дважды, вы можете получить разные результаты.И т. Д.

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

Некоторые хорошие компиляторы могут выдавать предупреждения, если вы используете чистые целочисленные константные выражения, такие как int x = 0/0;, но опять-таки это не работакомпилятор, чтобы найти эту ошибку.Это работа программиста.Поэтому вы должны всегда проверять, равен ли правый операнд / или % нулю, перед применением операндов.

2 голосов
/ 30 апреля 2019

Как видно на в проводнике компилятора Годболта , оба gcc и clang оптимизируют n / n для n целых чисел, чтобы оценить до 1 без какого-либо предупреждения.gcc выполняет эту оптимизацию даже при -O0, тогда как clang генерирует код операции деления для -O0, но оптимизированная альтернатива для -O1 и выше.

0 / 0 имеетв любом случае неопределенное поведение, поэтому любое поведение для n / n в порядке, если n равно нулю, включая оценку до 1 без видимого побочного эффекта.

Если вы настаиваете, вы можете квалифицировать n какvolatile и компилятор может сгенерировать деление, как и gcc, и clang в этом случае, но если n читается дважды, это не обязательно.

2 голосов
/ 30 апреля 2019

Компиляторам разрешается предполагать, что код не вызывает неопределенного поведения, и использовать это предположение при оптимизации кода.

Для любого значения, отличного от n==0, выражение n/n оценивается как 1. Поскольку погружение на ноль - неопределенное поведение в C, компилятор может предположить, что этот сценарий никогда не происходит, то есть он может предположить, чтоn!=0.Поскольку это может предполагать, что компилятор может заменить медленный n/n дешевым постоянным значением 1.Вероятно, именно это и происходит с рассматриваемым кодом.

Конечно, компилятору не требуется делать какие-либо подобные предположения, и он может генерировать фактическое деление.В зависимости от аппаратного обеспечения, которое выполняет код, конкретный аппаратный сигнал (или исключение) может сработать в таком случае деления на ноль.Я сомневаюсь, что любой разумный компилятор будет генерировать деление в этом примере для оптимизированного кода , потому что деление очень медленное, и согласно стандарту константа 1 достаточно хороша.Тем не менее, вполне вероятно, что в режиме отладки произойдет фактическое деление.

Подобные вещи случаются при оптимизации другого неопределенного поведения, такого как int overflow:

void f(int x)
{
   if (x > x + 1) 
       // executed only in case of overflow,
       // which is undefined behavior, 
       // and hence likely optimized out.
       overflow_error();
   ...

Don 'не полагайтесь на неопределенное поведение - оно не предсказуемо.

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