fscanf не может обнаружить ошибку сопоставления. ошибка libc или нет?

Проблема в следующем:


#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  float f = 0.0f;
  int n = 0;

  n = fscanf(stdin, "%f", &f);
  printf("n = %d, f = %f\n", n, f);

  return 0;
}

Он печатает:

n = 1, f = 100.0000

Если входная строка:

100 эргов

был предоставлен stdin. Следующее поведение происходит в gcc (4.8.1) и VS2010 (и ниже). Это ошибка, или я что-то пропустил здесь? Потому что в стандарте c (c89) в разделах 7.19.6.2.19 и 7.19.6.2.20 четко указано, что n должно быть равно нулю из-за ошибки сопоставления.

УПД. просто дополнительная информация:

1) пример из стандарта:

http://port70.net/~nsz/c/c99/n1256.html#7.19.6.2p20 (спасибо Крису Калтеру за ссылку)

2) аналогичный пример для сопоставления отказа, который работает по назначению:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int hex = 0x0;
  int n = 0;

  n = fscanf(stdin, "%x", &hex);
  printf("n = %d, hexVal = %x\n", n, hex);

  return 0;
}

если стандартный ввод содержит 0xz, вывод

n = 0, hexVal = 0


person HighPredator    schedule 27.10.2014    source источник
comment
Это не соответствующий провал. Сопоставление останавливается при обнаружении «е» и «эрг» не анализируется. Если вам нужно более точное управление, рассмотрите возможность использования strtod, что, конечно, означает, что вы должны сначала прочитать строку из stdin.   -  person M Oehm    schedule 27.10.2014
comment
Хорошо, но в стандарте в приведенных выше разделах четко указано, что именно в этом случае (пример примерно такой же с тем же вводом), что это ЯВЛЯЕТСЯ ошибкой сопоставления. Вот что меня смущает...   -  person HighPredator    schedule 27.10.2014
comment
@HighPredator, я не хочу слишком сильно редактировать ваш вопрос, но вы можете процитировать 7.19.6.2.20 черновика C99 и дать ссылку на port70.net/~nsz/c/c99/n1256.html#7.19.6.2p20 для доказательства. Строку count = 0; // "100e" fails to match "%f" важно видеть.   -  person Chris Culter    schedule 27.10.2014
comment
@ChrisCulter, спасибо за ссылку.   -  person HighPredator    schedule 27.10.2014
comment
Нет проблем, я получил его от stackoverflow.com/a/17015061 :)   -  person Chris Culter    schedule 27.10.2014
comment
Хорошо, теперь я вижу, что 100e следует считать неполной экспонентой и, следовательно, ошибкой сопоставления. (Я предпочитаю нестандартный способ не относиться к э/э как к чему-то особенному, так что, может быть, это молчаливое улучшение?)   -  person M Oehm    schedule 27.10.2014


Ответы (2)


Если они не внесли изменений в окончательный стандарт, поведение, которое вы видите, является ошибкой. (Спасибо HighPredator за ссылку)

Разница между scanf() и strtol()/strtod() в разбор чисел.

person Klas Lindbäck    schedule 27.10.2014
comment
Это что-то новое. Я такого нигде не видел. Можете дать ссылку? Потому что у меня сложилось впечатление, что группа scanf и группа strto.. — это механически разные функции. - person HighPredator; 27.10.2014
comment
Да, видимо, они действительно механически разные. stackoverflow .com/questions/1425730/ - person HighPredator; 27.10.2014
comment
@HighPredator Я неправильно прочитал связанный черновик. Похоже, это ошибка. Спасибо, что указали на это. - person Klas Lindbäck; 27.10.2014

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

int i, j;
fscanf(stdin, "%d", &i);
fscanf(stdin, "%d", &j);

и

int i, j;
fscanf(stdin, "%d%d", &i, &j);

и если вы кормите 1 2, вы получите i=1, j=2

Что вы ожидаете от этого:

float f = 0.0f;
int n = 0;
char c[16];

n = fscanf(stdin, "%f", &f);
printf("n = %d, f = %f\n", n, f);
n = fscanf(stdin, "%15s", c);
printf("n = %d, string = %s\n", n, c);

При фиде с 100erg вы получаете:

n = 1, f = 100.0000
n = 1, string = erg

Таким образом, текущий результат fscanf совершенно правильный, потому что 100 допустимо в качестве входного числа с плавающей запятой.

person Serge Ballesta    schedule 27.10.2014
comment
Это то, что я пытаюсь указать. Так что текущий результат fscanf совершенно правильный. Это не так, с точки зрения приведенного выше примера стандарта. Во-вторых, часть 100e 100erg является действительным префиксом в соответствии с описанием из 6.4.4.2. Из-за этого imho стандарт требует, чтобы в этом случае scanf возвращал ноль. - person HighPredator; 27.10.2014
comment
Похоже нумерация моего абзаца отличается от этой... Во всяком случае, вот о чем я говорил port70.net/~nsz/c/c89/c89-draft.html#3.1.3.1 - person HighPredator; 27.10.2014
comment
Проще говоря, как я это вижу: 100e является допустимым префиксом для значения с плавающей запятой в экспоненциальной форме (точно так же, как 0x для шестнадцатеричного), затем после него стандартный ввод не содержит допустимой цифровой части. При этом должен произойти совпадающий случай неудачи (так же, как с шестнадцатеричным) и должен быть возвращен ноль. - person HighPredator; 27.10.2014
comment
@HighPredator: мы на темной стороне. Я попробовал это в MSVC2008, и он разбивает 100e (дает 100.) и rg, но clang 3.1 и gcc 4.2.1 (FreeBSD 9.0) разделяют 100 и erg. У меня нет последних доступных компиляторов, чтобы посмотреть, изменится ли он с ними. - person Serge Ballesta; 27.10.2014