C++: atof() имеет неправильное поведение

Я использую библиотеку для загрузки файлов Wavefront .obj в свое приложение OpenGL ( tinyobjloader). Я заметил, что при загрузке объектов возникает ошибка. Когда я загружаю объект с координатой, например. 0.9999999, это установлено в 0. Отладкой я обнаружил, что следующий метод производит это поведение:

static inline float parseFloat(const char*& token)
{
    token += strspn(token, " \t");
    float f = (float)atof(token);
    token += strcspn(token, " \t\r");
    return f;
}

Так что atof() возвращает int, а не float. Я читал, что некоторые компиляторы не выдают предупреждение при использовании atof() без включения "stdlib.h", и в результате atof() возвращает целое число.

Любопытно, что даже если я включу "stdlib.h", ошибка останется. Я не могу понять, что вызывает такое поведение.

Любая идея?

2 ответа

Решение

Стандарт говорит atof:

За исключением поведения при ошибке, оно эквивалентно strtod(nptr,(char**)NULL)

так что возвращаемое вами "0" не имеет ничего общего с тем, что float не может представлять его или что-то подобное.

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

Это сильный признак того, что вы используете локаль, которая ожидает , вместо . в качестве десятичного разделителя. В зависимости от того, как ваше приложение работает с локалями, вы можете запустить его с правильно установленной переменной среды (например, LC_NUMERIC=C) или сделать setlocale(LC_NUMERIC,"C"); себя перед любым разбором.

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

Вы можете увидеть документацию atof здесь. Некоторые числа с плавающей запятой не могут быть представлены в 32 битах, и, следовательно, вы получаете ошибку и возвращаемое значение равно нулю.

//Try these 
float f = 0.9999999 ;
cout << atof("0.9999999") << " " << f << endl;//output is 1 1 

То, что вы видите, - это правильное поведение. Вы можете попробовать strtod()

Другие вопросы по тегам