Если функция не возвращает значения с допустимым типом возврата, можно ли компилятору выбрасывать мусор? - PullRequest
14 голосов
/ 30 марта 2012

Если функция имеет тип возвращаемого значения, отличный от void, и функция ничего не возвращает, то я думаю, что компилятор возвращает значение мусора (возможно, рассматривается как неинициализированное значение). Это происходит во время компиляции, так почему бы не выдать ошибку?

Например,

int func1() {
    return; // error
}

int func2() {
    // does not return anything
}

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

  int i;  // error
  int i = 6;  // okay

Есть мысли или это дублирующий вопрос? Я ценю вашу помощь.

Ответы [ 4 ]

16 голосов
/ 30 марта 2012

В C ++ такой код имеет неопределенное поведение:

[stmt.return] / 2 ... Выход из конца функции эквивалентен возвращению без значения; это приводит к неопределенному поведению в функции, возвращающей значение. ...

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

Стандарт C ++ не требует, чтобы это было ошибкой во время компиляции, потому что в общем случае было бы очень трудно правильно определить, действительно ли код выполняется в конце функции или если функция завершается через исключение ( или longjmp или аналогичный механизм).

Рассмотрим

int func3() {
    func4();
}

Если func4() выбрасывает, то этот код полностью в порядке. Компилятор, возможно, не сможет увидеть определение func4() (из-за отдельной компиляции) и поэтому не может знать, сгенерирует он или нет.

Более того, даже если компилятор может доказать, что func4() не выдает, ему все равно придется доказать, что func3() действительно вызывается, прежде чем он сможет законно отклонить программу. Такой анализ требует проверки всей программы, которая несовместима с отдельной компиляцией и которая даже не возможна в общем случае.

10 голосов
/ 30 марта 2012

In C, цитата N1256 6.9.1p12:

Если достигнута } , которая завершает функцию, и значение Вызов функции используется вызывающей стороной, поведение не определено.

Таким образом, законно (но это плохая идея) для функции, не являющейся пустым, не возвращать значение, но если это так и , вызывающая сторона пытается использовать результат, поведение не определено. Обратите внимание, что он не обязательно просто возвращает произвольное значение; Что касается стандарта, все возможно.

В пред-ANSI C не было ключевого слова void, поэтому способ написания функции, которая не возвращала значение, заключался в том, чтобы исключить возвращаемый тип, неявно возвращая int. Требование оператора return в функции, возвращающей значение, сломало бы старый код. Кроме того, компилятору потребовался бы дополнительный анализ, чтобы определить, что все пути кода попадают в оператор return; такой анализ является разумным для современных компиляторов, но, возможно, был чрезмерным бременем, когда C был впервые стандартизирован.

C ++ немного более строгий. В C ++:

Вывод из конца функции эквивалентен return с неважно; это приводит к неопределенному поведению в возвращающем значение функция.

, поэтому поведение не определено, пытается ли вызывающий использовать (несуществующий) результат или нет.

Компиляторы

C и C ++, конечно, могут предупредить о пропущенных return операторах или о путях управления, которые выходят за пределы функции без выполнения оператора return, но соответствующие стандарты не требуют им сделать это.

4 голосов
/ 30 марта 2012

В C на самом деле законно, что не пустая функция завершает работу без возврата значения, , если вызывающий код не пытается использовать возвращаемое значение .

* 1004.* С другой стороны, оператор return без выражения не может появляться в недействительной функции.

Соответствующие части стандарта C99 - §6.9.1 для первого случая:

Если достигнут }, который завершает функцию, и вызывающая сторона использует значение вызова функции, поведение не определено.

и §6.8.6.4 для второго случая:

Оператор return без выражения должен появляться только в функции, тип возвращаемой информации которой void.

2 голосов
/ 30 марта 2012

Обе ваши функции плохо сформированы. Разница между ними заключается в том, что ваш func1 нарушает правила использования оператора return, в то время как ваш func2 - неопределенное поведение. Оператор return в вашем func1 недопустим, и реализация должна это диагностировать. Отсутствие оператора return в вашем func2 - неопределенное поведение. Большинство компиляторов диагностируют это, но никто не должен.

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