Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

scanf: strange behavior?

5 views
Skip to first unread message

Egon Eckert

unread,
Sep 2, 2004, 10:41:52 AM9/2/04
to dj...@delorie.com
Hi,

compiling and running this code:

#include <stdio.h>

int main(int, const char**)
{
char c[2];
printf("%d\n", sscanf("A", "%c%c", c, c + 1));
return 0;
}

gives:

1 in GNU libc (on Linux)
1 in Borland C++ 3.1 (on DOS)
-1 in djgpp

It's conformant with the docs: "If input ends, or if there is any
input failure before the first item is converted and assigned, `EOF'
is returned.", so it's not to be called a 'bug', but...

Do you think it's a standard violation, or just a "difference",
ie. behavior not specified by POSIX, ANSI or other (involved)
authority?

Thanks,

--
Egon Eckert, Heaven Industries, s.r.o.
E-mail: eg...@heaven.industries.cz

Tornado

unread,
Sep 2, 2004, 10:48:40 AM9/2/04
to

>
> #include <stdio.h> ... #include <stdarg.h> ? ..??

Martin Str|mberg

unread,
Sep 2, 2004, 11:42:12 AM9/2/04
to
Egon Eckert <eg...@heaven.industries.cz> wrote:
> compiling and running this code:

> #include <stdio.h>

> int main(int, const char**)
> {
> char c[2];
> printf("%d\n", sscanf("A", "%c%c", c, c + 1));
> return 0;
> }

> gives:

> 1 in GNU libc (on Linux)
> 1 in Borland C++ 3.1 (on DOS)
> -1 in djgpp

> It's conformant with the docs: "If input ends, or if there is any
> input failure before the first item is converted and assigned, `EOF'
> is returned.", so it's not to be called a 'bug', but...

> Do you think it's a standard violation, or just a "difference",
> ie. behavior not specified by POSIX, ANSI or other (involved)
> authority?

It's a standard(1) violation in GNU libc and Borland C++ 3.1 (if your
report is accurate).


1. C99 (at least).


Right,

MartinS

Martin Ambuhl

unread,
Sep 2, 2004, 12:27:52 PM9/2/04
to
Egon Eckert wrote:

> Hi,
>
> compiling and running this code:
>
> #include <stdio.h>
>
> int main(int, const char**)

^^^^^^^^^^^^^^^^^^^^^^^^^^
After correcting this illegal and uncompilable line,

> {
> char c[2];
> printf("%d\n", sscanf("A", "%c%c", c, c + 1));
> return 0;
> }
>
> gives:
>
> 1 in GNU libc (on Linux)
> 1 in Borland C++ 3.1 (on DOS)
> -1 in djgpp

djgpp yields 1.

Don't complain about what happens when you try compiling garbage.

Martin Str|mberg

unread,
Sep 2, 2004, 12:38:52 PM9/2/04
to
Martin Ambuhl <mam...@earthlink.net> wrote:

> Egon Eckert wrote:
>> int main(int, const char**)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^
> After correcting this illegal and uncompilable line,

>> gives:


>>
>> 1 in GNU libc (on Linux)
>> 1 in Borland C++ 3.1 (on DOS)
>> -1 in djgpp

> djgpp yields 1.

Which is not compliant to the C99 standard.

I think Egon is using 2.04 (or even CVS version) and Martin 2.03.


Right,

MartinS

eg...@heaven.industries.cz

unread,
Sep 2, 2004, 2:40:05 PM9/2/04
to dj...@delorie.com
> >> int main(int, const char**)
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^
> > After correcting this illegal and uncompilable line,

You are kidding (a c++ hater perhaps?). I think this is legal c++,
and even valid main() prototype. Correct me if I'm wrong please.

> Which is not compliant to the C99 standard.
>
> I think Egon is using 2.04 (or even CVS version) and Martin 2.03.

You are right about me. It's the "last beta". I tried hard to
assemble a fairly recent but stable djgpp "distro" and I'm very
satisfied now (using gcc 3.3.4). I'm enjoying the mallinfo() (not in
2.03).

About the standard... I'm unfortunately unable to access it. I
purchased just the ISO c++ standard which, obviously, doesn't touch
things belonging to the C library. May be I should use iostreams then
:)), but I *so* dislike them.

Well, thanks for the explanation. Have to work around it. BTW the
API is pretty idiotic IMHO, why not return the count of stored/scanned
items always?

Egon

CBFalconer

unread,
Sep 2, 2004, 3:08:36 PM9/2/04
to
Egon Eckert wrote:
>
> compiling and running this code:
>
> #include <stdio.h>
>
> int main(int, const char**)
> {
> char c[2];
> printf("%d\n", sscanf("A", "%c%c", c, c + 1));
> return 0;
> }
>
> gives:
>
> 1 in GNU libc (on Linux)
> 1 in Borland C++ 3.1 (on DOS)
> -1 in djgpp
>
> It's conformant with the docs: "If input ends, or if there is any
> input failure before the first item is converted and assigned, `EOF'
> is returned.", so it's not to be called a 'bug', but...
>
> Do you think it's a standard violation, or just a "difference",
> ie. behavior not specified by POSIX, ANSI or other (involved)
> authority?

I think DJGPP is correct in returning EOF, because the string ends
before the scan is complete. The only authority is the C
standard. I would consider it a library bug on Borland and your
particular Linux installation of libc. This is better suited to
comp.lang.c.

At least all three signalled a failure.

--
Some useful references:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> C-library


Brian Inglis

unread,
Sep 2, 2004, 3:59:24 PM9/2/04
to
On Thu, 02 Sep 2004 19:08:36 GMT in comp.os.msdos.djgpp, CBFalconer
<cbfal...@yahoo.com> wrote:

>Egon Eckert wrote:
>>
>> compiling and running this code:
>>
>> #include <stdio.h>
>>
>> int main(int, const char**)
>> {
>> char c[2];
>> printf("%d\n", sscanf("A", "%c%c", c, c + 1));
>> return 0;
>> }
>>
>> gives:
>>
>> 1 in GNU libc (on Linux)
>> 1 in Borland C++ 3.1 (on DOS)
>> -1 in djgpp
>>
>> It's conformant with the docs: "If input ends, or if there is any
>> input failure before the first item is converted and assigned, `EOF'
>> is returned.", so it's not to be called a 'bug', but...
>>
>> Do you think it's a standard violation, or just a "difference",
>> ie. behavior not specified by POSIX, ANSI or other (involved)
>> authority?
>
>I think DJGPP is correct in returning EOF, because the string ends
>before the scan is complete. The only authority is the C
>standard. I would consider it a library bug on Borland and your
>particular Linux installation of libc. This is better suited to
>comp.lang.c.

Wrong way round.

>At least all three signalled a failure.

GNU "info libc a scanf" and the standard agree that EOF is returned
only if an input failure (terminator or eof, error) occurs before
*any* match, including any literal strings and suppressed assignments,
and only assignments due to matched input are counted in the return
value, excluding %n and suppressed assignments, so scanf returns EOF
only on early input failure, and >= *0* on later input failure,
matching failure, or success of course.

--
Thanks. Take care, Brian Inglis Calgary, Alberta, Canada

Brian....@CSi.com (Brian[dot]Inglis{at}SystematicSW[dot]ab[dot]ca)
fake address use address above to reply

DJ Delorie

unread,
Sep 2, 2004, 4:30:34 PM9/2/04
to dj...@delorie.com

IIRC this was discussed on comp.std.c recently, and the djgpp-workers
list (er, last March). We don't need to discuss it again, we just
need to make sure the right way is implemented.

IIRC it was a choice between "correct" or "compatible". Either way,
someone is going to be disappointed.

Cesar Rabak

unread,
Sep 2, 2004, 5:01:54 PM9/2/04
to
eg...@heaven.industries.cz escreveu:

>>>>int main(int, const char**)
>>>
>>> ^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>After correcting this illegal and uncompilable line,
>>
>
> You are kidding (a c++ hater perhaps?). I think this is legal c++,
> and even valid main() prototype. Correct me if I'm wrong please.

But: the use of the code above would be to collect arguments passed to
the command line _except_ yours have no variable to collect!

Since you have put in the body of your main, is no longer a prototype!

--
Cesar Rabak

Cesar Rabak

unread,
Sep 2, 2004, 5:03:40 PM9/2/04
to
DJ Delorie escreveu:

Can I surmise the implementation choice at DJGPP was the '"correct"'?

;-)

--
Cesar Rabak

DJ Delorie

unread,
Sep 2, 2004, 5:41:03 PM9/2/04
to dj...@delorie.com

> Can I surmise the implementation choice at DJGPP was the '"correct"'?

I don't recall offhand if the current (or past) implementation in
DJGPP was fully correct or not, but if it's different from glibc or
borland, it's certainly not the "compatible" option ;-)

DJ Delorie

unread,
Sep 2, 2004, 5:44:13 PM9/2/04
to dj...@delorie.com

> But: the use of the code above would be to collect arguments passed to
> the command line _except_ yours have no variable to collect!
>
> Since you have put in the body of your main, is no longer a prototype!

You apparently don't understand C++ enough.

The prototype given indicates that the function expects to be passed
two arguments, but does not need to reference them. It is a
consequence of the ability to have *some* of the arguments unnamed as
placeholders (so that you don't get a warning about not using a named
parameter). Consider:

int foo (char *a, int, int b) { }

The second parameter indicates that something *is* passed, and foo
*knows* about it, but doesn't use it.

Compare:

int main() { }

This means that main doesn't expect any parameters.

int main(int, char **) { }

This means that main expects parameters, but won't use them.

Cesar Rabak

unread,
Sep 2, 2004, 6:09:33 PM9/2/04
to
DJ Delorie escreveu:

>>But: the use of the code above would be to collect arguments passed to
>>the command line _except_ yours have no variable to collect!
>>
>>Since you have put in the body of your main, is no longer a prototype!
>
>
> You apparently don't understand C++ enough.

As I wrote in the snipped you kept, I was questioning the definition, no
the declaration, since the main was at a body of a small program.

Egon Eckert

unread,
Sep 2, 2004, 6:11:57 PM9/2/04
to dj...@delorie.com
> > But: the use of the code above would be to collect arguments passed to
> > the command line _except_ yours have no variable to collect!
> >
> > Since you have put in the body of your main, is no longer a prototype!
>
> You apparently don't understand C++ enough.

Thank you for my defence. It's hard for me (without a brand name in
this mailing list) to defend against acm.org member ending each
sentence with an exclamation mark. :)

Anyway, reading this again and again (libc.inf/scanf)--

Return Value
------------

The number of items successfully matched and assigned. If input ends,


or if there is any input failure before the first item is converted and
assigned, `EOF' is returned.

-- I'm becoming more and more confident, that it's actually
inconsistent with the current implementation.

To return EOF, the input has to end *before* the first item
converted/assigned, because when it has to end otherwise? It has to
end sometime... No word about conversion items pending.

Egon

DJ Delorie

unread,
Sep 2, 2004, 6:30:56 PM9/2/04
to dj...@delorie.com

> -- I'm becoming more and more confident, that it's actually
> inconsistent with the current implementation.
>
> To return EOF, the input has to end *before* the first item
> converted/assigned, because when it has to end otherwise? It has to
> end sometime... No word about conversion items pending.

The documentation is vague (heck, the standard is a little vague too).
The problem is that it doesn't say what happens when they're
successful conversions AND input ends prematurely. The normal case is
that you have a conversion for all your format specifiers before input
ends. The other two cases are a conversion error (wrong input) or end
of string (no input).

The appropriate test cases are thus, for "%d %d":

""
"x"
"5"
"5 x"
"5 5"
"5 5 x"

The first and third are the problem cases here.

DJ Delorie

unread,
Sep 2, 2004, 6:31:47 PM9/2/04
to dj...@delorie.com

> As I wrote in the snipped you kept, I was questioning the
> definition, no the declaration, since the main was at a body of a
> small program.

I know. In C++ that's legal.

Brian Inglis

unread,
Sep 2, 2004, 8:21:05 PM9/2/04
to
On Thu, 2 Sep 2004 18:30:56 -0400 in comp.os.msdos.djgpp, DJ Delorie
<d...@delorie.com> wrote:

>
>> -- I'm becoming more and more confident, that it's actually
>> inconsistent with the current implementation.
>>
>> To return EOF, the input has to end *before* the first item
>> converted/assigned, because when it has to end otherwise? It has to
>> end sometime... No word about conversion items pending.
>
>The documentation is vague (heck, the standard is a little vague too).
>The problem is that it doesn't say what happens when they're
>successful conversions AND input ends prematurely. The normal case is
>that you have a conversion for all your format specifiers before input
>ends. The other two cases are a conversion error (wrong input) or end
>of string (no input).

ISTM the standard clearly specifies only input failure *before* any
conversion occurs results in EOF: any matching failure results in the
number of matched, converted and assigned items being returned, which
may be zero:

"7.19.6.2#16 The fscanf function returns the value of the macro EOF if
an input failure occurs before any conversion. Otherwise, the function
returns the number of input items assigned, which can be fewer than
provided for, or even zero, in the event of an early matching
failure."

>The appropriate test cases are thus, for "%d %d":

IMHO according to info and standard, results should be:
> ""
input failure - terminator - returns EOF
> "x"
matching failure - returns 0
> "5"
input failure - terminator - returns 1
> "5 x"
matching failure - returns 1
> "5 5"
success - returns 2
> "5 5 x"
success - returns 2 - " " scanned and pushed back - "x" unscanned


>
>The first and third are the problem cases here.

--

DJ Delorie

unread,
Sep 2, 2004, 8:35:48 PM9/2/04
to dj...@delorie.com

> "7.19.6.2#16 The fscanf function

It's sscanf that's the interesting one.

Martin Ambuhl

unread,
Sep 2, 2004, 8:44:51 PM9/2/04
to
eg...@heaven.industries.cz wrote:

>>>>int main(int, const char**)
>>>
>>> ^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>After correcting this illegal and uncompilable line,
>
>
> You are kidding (a c++ hater perhaps?). I think this is legal c++,
> and even valid main() prototype. Correct me if I'm wrong please.

I'm sorry. I was misled by the C inclusion
#include <stdio.h>
where a C++ program would have
#include <cstdio>

Are you a hater of C++, perhaps?
BTW, there is no mention of C++ in your code. Using the C header rather
than the C++ header and code that, apart from the one line I pointed
out, looks much more like code a C programmer would write than that a
C++ programmer would write.

Since your code is neither standard C nor standard C++, is there some
reason I should assume your unlabeled C-looking code was intended to be C++?

DJ Delorie

unread,
Sep 2, 2004, 9:02:46 PM9/2/04
to dj...@delorie.com

> I'm sorry. I was misled by the C inclusion
> #include <stdio.h>

This is perfectly legal C++ too.

DJ Delorie

unread,
Sep 2, 2004, 9:06:12 PM9/2/04
to dj...@delorie.com

> I'm sorry. I was misled by the C inclusion
> #include <stdio.h>
> where a C++ program would have
> #include <cstdio>

Also, the original poster noted that a C++ compiler was used:

CBFalconer

unread,
Sep 2, 2004, 10:17:29 PM9/2/04
to

I just got around to running it under DJGPP 2.03, and got 1.

--
Some similarities between GWB and Mussolini:
a) The strut; b) Making war until brought up short:
Mussolini: Ethiopia, France, Greece.
GWB: Afghanistan, Iraq.


CBFalconer

unread,
Sep 3, 2004, 1:03:28 AM9/3/04
to
Brian Inglis wrote:
> DJ Delorie <d...@delorie.com> wrote:
>
... snip ...

>
> "7.19.6.2#16 The fscanf function returns the value of the macro EOF if
> an input failure occurs before any conversion. Otherwise, the function
> returns the number of input items assigned, which can be fewer than
> provided for, or even zero, in the event of an early matching
> failure."
>
> >The appropriate test cases are thus, for "%d %d":
>
> IMHO according to info and standard, results should be:
> > ""
> input failure - terminator - returns EOF
> > "x"
> matching failure - returns 0
> > "5"
> input failure - terminator - returns 1
> > "5 x"
> matching failure - returns 1
> > "5 5"
> success - returns 2
> > "5 5 x"
> success - returns 2 - " " scanned and pushed back - "x" unscanned

I agree with your interpretation. AFAICS DJGPP 2.03 complies.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews


CBFalconer

unread,
Sep 3, 2004, 1:03:29 AM9/3/04
to

Which is quite capable of compiling C code.

Brian Inglis

unread,
Sep 3, 2004, 1:23:17 AM9/3/04
to

Not too different, except string nul terminator is treated the same as
an input file EOF:

"7.19.6.7#2 The sscanf function is equivalent to fscanf, except that
input is obtained from a string (specified by the argument s) rather
than from a stream. Reaching the end of the string is equivalent to
encountering end-of-file for the fscanf function. If copying
takes place between objects that overlap, the behavior is undefined.
Returns
3 The sscanf function returns the value of the macro EOF if an input
failure occurs before any conversion. Otherwise, the sscanf function


returns the number of input items assigned, which can be fewer than
provided for, or even zero, in the event of an early matching
failure."

--

Gisle Vanem

unread,
Sep 3, 2004, 4:17:13 AM9/3/04
to djgpp

Hasn't anybody mentioned that sscanf() in djgpp 2.04 has a bug?
Don't know who reported it first, but I did here:
http://www.delorie.com/archives/browse.cgi?p=djgpp-workers/2004/03/27/06:45:38

So the OP uses 2.04 and sees the result of this bug?
(since 2.03 produces the expected result).

It seems the bug has been fixed now (by Martin S.?) This
http://www.ludd.luth.se/~ams/djgpp/cvs/djgpp/src/libc/ansi/stdio/doscan.c

hash a timestamp of 3 Sep 2004. Good work.

--gv

Martin Str|mberg

unread,
Sep 5, 2004, 5:43:37 AM9/5/04
to
Martin Str|mberg <a...@speedy.ludd.ltu.se> wrote:
> Egon Eckert <eg...@heaven.industries.cz> wrote:
>> compiling and running this code:

>> #include <stdio.h>

>> int main(int, const char**)
>> {
>> char c[2];
>> printf("%d\n", sscanf("A", "%c%c", c, c + 1));
>> return 0;
>> }

>> gives:

>> 1 in GNU libc (on Linux)
>> 1 in Borland C++ 3.1 (on DOS)
>> -1 in djgpp

> It's a standard(1) violation in GNU libc and Borland C++ 3.1 (if your
> report is accurate).

> 1. C99 (at least).

I have to retract my words. I was thinking of another case (see
another follow-up in this thread). So right now I think 1 is the right
return value.


Right,

MartinS

Martin Str|mberg

unread,
Sep 5, 2004, 6:02:58 AM9/5/04
to
DJ Delorie <d...@delorie.com> wrote:

> IIRC this was discussed on comp.std.c recently, and the djgpp-workers
> list (er, last March). We don't need to discuss it again, we just
> need to make sure the right way is implemented.

Not on comp.std.c if my memory and search is correct. What was
discussed there was what should be returned if there are suppressed
assignments in combination with input failure. Links:
<http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&frame=right&th=96bf8969887ac993&seekm=4057500f%240%2496976%24cc7c7865%40news.luth.se#s>
<http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&frame=right&th=410bb8eb9e4390ac&seekm=3f342e20%240%24165%24cc7c7865%40news.luth.se#s>

I see that I noticed there is a problem in libc regarding returning
EOF and the test program:
<http://www.delorie.com/djgpp/mail-archives/browse.cgi?p=djgpp-workers/2004/03/09/14:24:30>.
I don't remember but I think I corrected the underlying function (that
*scanf() call) to work according to the corrected test program.

So if anyone wants to verify that I did so: check the CVS log that I
did some correction regarding this, get CVS libc and test programs,
check the test programs that you agree and compile the lot and check
if it's right.

> IIRC it was a choice between "correct" or "compatible". Either way,
> someone is going to be disappointed.

If the above is right, I suspect the correct behaviour hasn't gotten
around to the users yet. And I think that correct might be ==
compatible too.


Right,

MartinS

Martin Str|mberg

unread,
Sep 5, 2004, 6:06:26 AM9/5/04
to
Egon Eckert <eg...@heaven.industries.cz> wrote:
> -- I'm becoming more and more confident, that it's actually
> inconsistent with the current implementation.

You have to be careful about what is the current implementation... See
my other reply in this thread (I think I've found this bug and
corrected it in CVS).


Right,

MartinS

Martin Str|mberg

unread,
Sep 5, 2004, 6:08:29 AM9/5/04
to
DJ Delorie <d...@delorie.com> wrote:
> Also, the original poster noted that a C++ compiler was used:

>> 1 in Borland C++ 3.1 (on DOS)

Except that is (or perhaps purports to be) a C compiler too.


Right,

MartinS

Martin Str|mberg

unread,
Sep 5, 2004, 6:12:24 AM9/5/04
to
Gisle Vanem <gi...@bgnett.no> wrote:
> It seems the bug has been fixed now (by Martin S.?) This

I think to have corrected it. At least the test cases we have didn't
complain.

> http://www.ludd.luth.se/~ams/djgpp/cvs/djgpp/src/libc/ansi/stdio/doscan.c

> hash a timestamp of 3 Sep 2004. Good work.

Umm... No, it has a timestamp of 09-Apr-2004 06:08.


Right,

MartinS

0 new messages