Cerrno не работает, но ошибка исправлена в Xcode (11.6)

#c #xcode #compiler-errors #c-strings

#c #xcode #ошибки компилятора #c-строки

Вопрос:


Редактировать: Ошибка, похоже, работает. Например, если errno = ERANGE, выводится «Результат слишком большой».

Проблема остается в том, что значение errno не изменяется с 0.


В Xcode я пробовал cerrno и strerror с приведенным ниже коротким кодом. Xcode возвращает

sqrt(-1) = nan

Неопределенная ошибка: 0

вместо

sqrt(-1) = -nan

Числовой аргумент вне домена,

как это происходит, например, cpp.sh.

Почему это происходит?

 #include <iostream>
#include <iomanip>
#include <cmath>
#include <cerrno>
#include <cstring>

using namespace std;

int main() {

  errno = 0;
  cout << "sqrt(-1) = " << sqrt(-1) << endl;
  cout << strerror(errno) << endl << endl;
       
  return(0); 
}
  

Комментарии:

1. Прежде всего, чтобы удовлетворить мое любопытство (но может быть полезно), не могли бы вы показать нам значение вашего компилятора для math_errhandling макроса; например, добавьте эту строку: cout << "math_errhandling = " << math_errhandling << endl; ?

2. Привет, он добавляет «math_errhandling = 2».

3. Тогда это все объясняет.

4. Что ж, в этом и заключается проблема! Для установки errno этот макрос должен включать 1 . (Должно быть 3, чтобы соответствовать C 11, IIRC). Но как это исправить… не знаю.

5. Можете ли вы просмотреть свои подробные настройки и / или параметры командной строки компилятора, чтобы узнать, установлен ли где-либо этот -fno-math-errno параметр; или просмотрите свой заголовок <cmath> для определения __NO_MATH_ERRNO__ . В качестве альтернативы попробуйте добавить #undef __NO_MATH_ERRNO__ перед вашими #include... строками.

Ответ №1:

Всякий раз, когда вы хотите проверить errno после операции, вы всегда должны проверять ее и, возможно, сохранять сразу после операции, которая ее устанавливает. Если вы выполняете другие вызовы функций в промежутках между этой проверкой, даже что-то такое простое, как печать на терминале, вы можете сбиваться errno .

Одна из возможных причин, по которой это errno становится 0 возможным, связана с тем фактом, что это обернуто в выражения stream, и нет гарантии, что iostream не устанавливает косвенно (или не отменяет настройку) errno посредством его реализации.

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

 #include <iostream>
#include <iomanip>
#include <cmath>
#include <cerrno>
#include <cstring>

int main() {

  errno = 0;
  
  // store errno immediately after the computation
  const auto result = std::sqrt(-1);
  const auto err = errno;

  // then print
  std::cout << "sqrt(-1) = " << result << std::endl;
  std::cout << std::strerror(err) << std::endl << std::endl;
       
  return 0; 
}
  

Редактировать: Судя по обсуждениям в комментариях OP, это, по-видимому, не является причиной того, что errno не установлено, а скорее из-за того, что math_errhandling установлено значение 2 . Я сохраняю этот ответ здесь по архивным причинам, поскольку код в исходном сообщении мог бы так же легко видеть этот результат по причинам, описанным здесь.

Комментарии:

1. Мой плохой; вскоре после публикации этого я увидел обсуждение о math_errhandling ответственности. Это неправильный ответ для вашей конкретной проблемы, но я все равно оставлю этот ответ в силе, поскольку это другой возможный источник почему errno может быть не таким, каким вы ожидаете (на случай, если кто-нибудь еще наткнется на этот вопрос)