#c
Вопрос:
Я озадачен тем, что значение errno не устанавливается ERANGE
после strtod()
попыток преобразовать строку с огромным действительным числом в число с двойной плавающей запятой.
Вот что происходит, когда я запускаю свой код:
Enter a real number: 5656565656565652622326352635236523652362356235
You entered 5656565656565652358969982685269310483757793280.000000.
Вот мой код:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int getDouble(char* prompt, double* doubleRealNumber);
int main(void)
{
double d;
getDouble("Enter a real number: ", amp;d);
printf("You entered %lf.n", d);
return 0;
}
int getDouble(char* prompt, double* doubleRealNumber)
{
int const MAXBUFSIZE = 1024;
char buf[MAXBUFSIZE]; // use 1KiB just to be sure
int success; // flag for successful conversion
do
{
printf("%s", prompt);
fflush(stdout);
if (!fgets(buf, MAXBUFSIZE, stdin))
{
// reading input failed:
return 1;
}
// have some input, convert it to integer:
char *endptr;
errno = 0; // reset error number
*doubleRealNumber = strtod(buf, amp;endptr);
if (errno == ERANGE)
{
printf("Sorry, this number is too small or too large.n");
success = 0;
}
else if (endptr == buf)
{
// no character was read
success = 0;
}
else if (*endptr amp;amp; *endptr != 'n')
{
// *endptr is neither end of string nor newline,
// so we didn't convert the *whole* input
success = 0;
}
else
{
success = 1;
}
} while (!success); // repeat until we got a valid real number
return 0;
}
Комментарии:
1. Почему вы ожидаете, что он будет «вне зоны досягаемости»?
2. Это похоже скорее на потерю точности, чем на выход за пределы досягаемости. Не каждое число в динамическом диапазоне (экспоненты) может быть точно представлено (мантиссой).
3. Попробуйте с помощью этого ввода:
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
4. В качестве общего замечания не следует использовать значение
errno
до проверки того, указывает ли возвращаемое значение функции, чтоerrno
оно имеет значение. Вы можете полагаться на неопределенное поведение.5. Это хороший момент — вы должны только проверить
errno
HUGE_VAL
, возвращается ли он.
Ответ №1:
на самом деле значение errno правильно устанавливается для УДАЛЕНИЯ при вводе очень большого (или очень маленького) числа.
Если ввести действительно большое число, например «100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000», для errno задано значение ERANGE, и выводится следующее: «Извините, это число слишком мало или слишком велико». Таким образом, опубликованный код действителен и работает должным образом.
Причина в том, что входной номер и выходной номер не совпадают в вопросе из-за потери точности, а не из-за диапазона. Не каждое число в динамическом диапазоне (экспоненты) может быть точно представлено (мантиссой).
Большое спасибо Бесполезному и Бармаглоту за то, что указали на это!
Комментарии:
1. Стоит отметить, что установлено ли
errno
значениеERANGE
on underflow, определяется реализацией.