2015-10-01 2 views
1

Я рассматриваю использовать функцию strtod(), чтобы преобразовать строку в двойной в C, который является siganture:strtod() двусмысленность: Ошибка формата и ноль преобразование

double strtod (const char* str, char** endptr); 

str будет строка, которая будет преобразована и endptr указатель, который должен быть установлен на первый символ после номера.

Документация говорит:

В случае успеха функция возвращает преобразованное число с плавающей запятой в качестве значения типа двойной. Если действительное преобразование не было выполнено, функция возвращает ноль (0.0).

Таким образом, насколько я понимаю, это не представляется возможным обнаружить ситуации, в которых str имеет ошибку формата (например, «Foo», «-3ab» или «3O3») от ситуаций, в которых str представляет 0 (например, «0», «0.000», «-0.0», «0e10»).

Как можно использовать функцию strtod(), чтобы избежать этой проблемы при преобразовании нуля?

EDIT: Я видел аналогичный вопрос here. Тем не менее, я думаю, что я не спрашиваю об этом, так как мой вопрос касается проблемы двусмысленности между 0 и ошибочно сформированной строкой, в то время как другая статья касается обнаружения ошибок формирования в целом.

+0

Дубликат http://stackoverflow.com/questions/5580975/problem-with-string-conversion-to-number-strtod –

+0

Смотрите также [Обоснование позади C библиотеки никогда не устанавливают значение errno в ноль] (http://programmers.stackexchange.com/a/209731) – wimh

+0

И смотрите [Обнаружение strtol failure] (http://stackoverflow.com/a/26083517/33499) как 'strtol 'ведет себя как' strtod' – wimh

ответ

2

Кроме того, если вы хотите обнаружить другие ошибки, такие как «3.14xyz», strtod вернет 3.14, но endptr укажет на «x», поэтому, если после strtod «endptr» не указывает на «str 'AND' endptr 'указывает на только пробел (или ТОЧНО 0, если вы хотите быть строгим), тогда' str 'действительно является допустимым поплавком. Также errno устанавливается в ERANGE, если строка 'str' вызовет переполнение.

Вот реализация этого:

bool isDouble(const char* s) 
{ 
    char* rest = (char*) s; 

    strtod(s, &rest); 

    if ((rest == s) || (errno == ERANGE)) 
    return false; 

    // If all WS after the last char used in the conversion, then the string is considered a 'clean float' 
    while ((*rest == ' ') || (*rest == '\t') || (*rest == '\n')) 
    ++rest; 

    return (*rest == 0); 
} 
+1

Почему бы не использовать ['isspace()'] (http: // linux.die.net/man/3/isspace) для обнаружения пробелов? – wimh

+0

Потому что я никогда не слышал о функции :-) Да, не похоже на плохую идею. Особенно, поскольку он реализован как макрос. – kzangeli

2

Именно поэтому у вас есть endptr. Если после вызова endptr == str, число не было разобрано.

+0

Не уверен, что это правильно во всех случаях ... например. если 'str' - это« 3ab4 », то str указывает на 3. После вызова strtod(), возврат fuction 3 (double) и« endptr »указывает на« a »(который является * первым символом после номера *), , т.е. 'str' + 1. Таким образом, это случай, когда есть ошибка формата, и условие 'endptr == str' не может обнаружить его. – fgalan

+0

@fgalan Это совсем не ошибка формата. Функция определена для синтаксического анализа и возврата максимального количества символов, которые она может, и в этом случае это всего лишь один символ. – Amit

+0

@fgalan, если вы хотите узнать, внесла ли вся str в результат (был разобран), просто проверьте, что '(* endptr == 0)' –

Смежные вопросы