2

The problem is the following:


#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;
}

It prints:

n = 1, f = 100.0000

If the input string is:

100ergs

has been supplied to stdin. The following behavior occurs on gcc (4.8.1) and VS2010 (and lower). Is this a bug, or am I missing something here? Because c standard (c89) in sections 7.19.6.2.19 and 7.19.6.2.20 clearly states that n should be equal to zero due to a matching failure.

UPD. just some additional info:

1) example from standard:

http://port70.net/~nsz/c/c99/n1256.html#7.19.6.2p20 (thx to Chris Culter for link)

2) similar example for matching failure which works as intended:

#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;
}

if stdin contains 0xz output is

n = 0, hexVal = 0

Chris Culter
  • 4,470
  • 2
  • 15
  • 30
HighPredator
  • 790
  • 4
  • 21
  • 1
    It's not a matching failure. Matching stops when encountering the 'e' and 'ergs' is unparsed. If you need more fine-granied control, consider using `strtod`, which of course means that you have to read a string from `stdin` first. – M Oehm Oct 27 '14 at 07:26
  • 2
    Ok, but the standard in the sections above does clearly state, that in that exact case (the example there is relatively same with same input) that it IS a matching failure. That's what confuses me... – HighPredator Oct 27 '14 at 07:33
  • 2
    @HighPredator, I don't want to edit your question too far, but you might want to quote from 7.19.6.2.20 of the C99 draft and link to http://port70.net/~nsz/c/c99/n1256.html#7.19.6.2p20 for proof. The line `count = 0; // "100e" fails to match "%f"` is important to see. – Chris Culter Oct 27 '14 at 07:38
  • No prob, I got it from http://stackoverflow.com/a/17015061 :) – Chris Culter Oct 27 '14 at 07:46
  • Okay, I now see that "100e" should be considered an incomplete exponent and hence a matching failure. (I prefer the non-standard way of not treating e/E special, so maybe it's a silent "improvement"?) – M Oehm Oct 27 '14 at 08:11

2 Answers2

1

Unless they made changes in the final standard, the behaviour you see is a bug. (Thanks HighPredator for the link)

Difference between scanf() and strtol() / strtod() in parsing numbers.

Community
  • 1
  • 1
Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
  • That's something new. I've never seen that anywhere. Can you provide a link? Cause I was under the impression that scanf group and strto.. group are mechanically different functions. – HighPredator Oct 27 '14 at 08:45
  • Yep, apparently they indeed are mechanically different. http://stackoverflow.com/questions/1425730/difference-between-scanf-and-strtol-strtod-in-parsing-numbers – HighPredator Oct 27 '14 at 08:47
  • @HighPredator I misread the linked draft. It seems like it is a bug. Thanks for pointing it out. – Klas Lindbäck Oct 27 '14 at 09:00
0

You are reading from a stream. fscanf gets all acceptable characters ... and leave the rest for next read operation. In C, the two following snippets give same results :

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

and

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

and if you feed with 1 2, you'll get i=1, j=2

What would you expect from this :

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);

When feed with 100erg you get :

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

So current fscanf result is perfectly correct, because 100 is acceptable as an input float.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • That's what i'm trying to point out. "So current fscanf result is perfectly correct." It is not, in terms of the standard's example above. Secondly, 100erg's part 100e is a valid "prefix" in accordance with description from 6.4.4.2. Due to that imho the standard demands scanf to return zero in this case. – HighPredator Oct 27 '14 at 10:22
  • Looks like my paragraph's numeration differs from this one... Anyway, here's what i was talking about http://port70.net/~nsz/c/c89/c89-draft.html#3.1.3.1 – HighPredator Oct 27 '14 at 10:23
  • In simple words the way i see it: 100e is a valid "prefix" for floating point value in exponential form (just like 0x for hex) then, after it, stdin does not contain valid digit part. At such, matching failure case should occur (just like with hex) and zero should be returned. – HighPredator Oct 27 '14 at 10:27
  • @HighPredator : we are at the dark side. I tried it in MSVC2008 and it splits `100e` (gives `100.`) and `rg`, but clang 3.1 and gcc 4.2.1 (FreeBSD 9.0) split `100` and `erg`. I do not have recent compilers available to see if it changes with them. – Serge Ballesta Oct 27 '14 at 10:47