Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Question about va_list (http://www.velocityreviews.com/forums/t582753-question-about-va_list.html)

Fred 01-07-2008 05:43 AM

Question about va_list
 
I've got following program encapsuled fscanf, however, it doesn't
work.
I'm sure that the content format in "a.txt" is OK, the content would
be correctly read if using fscanf directly, what's wrong with my
program? Thanks for help!

int vsscanf( FILE* fp, const char *fmt, ... )
{
va_list arglist;
va_start( arglist, fmt );
return fscanf(fp, fmt, arglist);
}

int main()
{
FILE* fp = fopen( "C:\\a.txt", "r" );
if( fp == 0 )
{
printf( "%s\n", "Open File Error!" );
exit(-1);
}

char buffer[128];
char buffer2[128];
memset( buffer, 0, 128 );
vsscanf( fp, "%s\n", buffer );
printf( "%s\n", buffer );

return 1;
}

Ark Khasin 01-07-2008 06:35 AM

Re: Question about va_list
 
Fred wrote:
> I've got following program encapsuled fscanf, however, it doesn't
> work.
> I'm sure that the content format in "a.txt" is OK, the content would
> be correctly read if using fscanf directly, what's wrong with my
> program? Thanks for help!
>
> int vsscanf( FILE* fp, const char *fmt, ... )
> {
> va_list arglist;
> va_start( arglist, fmt );
> return fscanf(fp, fmt, arglist);
> }

A few problems:
- no va_end
- wrong argument list to fscanf after fmt.
It just /may/ happen by chance and in some compilers that it would work,
e.g. if va_list is a bunch on stack, and fp and fmt passed in registers.
But in most cases it won't.

However, what you have as a type of vsscanf seems to exist already under
the name of fscanf...
Presumably, you wanted to write the opposite, like
int vfscanf(FILE *fp, const char *fmt, va_list arglist);
That is accomplished easily - by modifying a source of your fscanf().
But why would you need it?

- Ark

Keith Thompson 01-07-2008 06:57 AM

Re: Question about va_list
 
Fred <hn.ft.pris@gmail.com> writes:
> I've got following program encapsuled fscanf, however, it doesn't
> work.


You say "it doesn't work". How exactly doesn't it work? What results
did you get, what did you expect, and how did they differ?

Recommended reading:
<http://www.catb.org/~esr/faqs/smart-questions.html>.

> I'm sure that the content format in "a.txt" is OK, the content would
> be correctly read if using fscanf directly, what's wrong with my
> program? Thanks for help!


It's difficult to be certain, because you didn't show us your complete
program. Presumably you have #include directives for at least
<stdio.h> and <stdarg.h>. You *should* also have #includes for
<string.h> and <stdlib.h>.

> int vsscanf( FILE* fp, const char *fmt, ... )
> {
> va_list arglist;
> va_start( arglist, fmt );
> return fscanf(fp, fmt, arglist);
> }
>
> int main()


Slightly better: "int main(void)".

> {
> FILE* fp = fopen( "C:\\a.txt", "r" );
> if( fp == 0 )
> {
> printf( "%s\n", "Open File Error!" );
> exit(-1);


Minor quibble: "exit(-1)" is non-portable. The only portable
arguments to exit() are 0, EXIT_SUCCESS, and EXIT_FAILURE.

> }
>
> char buffer[128];
> char buffer2[128];


You never use this.

> memset( buffer, 0, 128 );


Why the memset?

> vsscanf( fp, "%s\n", buffer );
> printf( "%s\n", buffer );
>
> return 1;


See "Minor quibble" above. Why not "return 0;"?

> }


The real problem is that you're trying to pass a va_list to fscanf().
In this particular call, the format argument is "%s\n", which means
the third argument should be a char*, not a va_list.

You're probably looking for vfscanf(). What you're trying to do in
this program is equivalent to just calling fscanf() directly, but
presumably you're going to do some more stuff in your vsscanf().

Incidentally, fscanf() with a "%s" format is potentially dangerous,
unless you can be sure that the input won't overflow your buffer.
(scanf() with a "%s" format is even more dangerous, since you
generally don't have complete control over what will appear on stdin.)

--
Keith Thompson (The_Other_Keith) <kst-u@mib.org>
[...]
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Fred 01-07-2008 09:04 AM

Re: Question about va_list
 
On Jan 7, 2:57 pm, Keith Thompson <ks...@mib.org> wrote:
> Fred <hn.ft.p...@gmail.com> writes:
> > I've got following program encapsuled fscanf, however, it doesn't
> > work.

>
> You say "it doesn't work". How exactly doesn't it work? What results
> did you get, what did you expect, and how did they differ?
>
> Recommended reading:
> <http://www.catb.org/~esr/faqs/smart-questions.html>.
>
> > I'm sure that the content format in "a.txt" is OK, the content would
> > be correctly read if using fscanf directly, what's wrong with my
> > program? Thanks for help!

>
> It's difficult to be certain, because you didn't show us your complete
> program. Presumably you have #include directives for at least
> <stdio.h> and <stdarg.h>. You *should* also have #includes for
> <string.h> and <stdlib.h>.
>
> > int vsscanf( FILE* fp, const char *fmt, ... )
> > {
> > va_list arglist;
> > va_start( arglist, fmt );
> > return fscanf(fp, fmt, arglist);
> > }

>
> > int main()

>
> Slightly better: "int main(void)".
>
> > {
> > FILE* fp = fopen( "C:\\a.txt", "r" );
> > if( fp == 0 )
> > {
> > printf( "%s\n", "Open File Error!" );
> > exit(-1);

>
> Minor quibble: "exit(-1)" is non-portable. The only portable
> arguments to exit() are 0, EXIT_SUCCESS, and EXIT_FAILURE.
>
> > }

>
> > char buffer[128];
> > char buffer2[128];

>
> You never use this.
>
> > memset( buffer, 0, 128 );

>
> Why the memset?
>
> > vsscanf( fp, "%s\n", buffer );
> > printf( "%s\n", buffer );

>
> > return 1;

>
> See "Minor quibble" above. Why not "return 0;"?
>
> > }

>
> The real problem is that you're trying to pass a va_list to fscanf().
> In this particular call, the format argument is "%s\n", which means
> the third argument should be a char*, not a va_list.
>
> You're probably looking for vfscanf(). What you're trying to do in
> this program is equivalent to just calling fscanf() directly, but
> presumably you're going to do some more stuff in your vsscanf().
>
> Incidentally, fscanf() with a "%s" format is potentially dangerous,
> unless you can be sure that the input won't overflow your buffer.
> (scanf() with a "%s" format is even more dangerous, since you
> generally don't have complete control over what will appear on stdin.)
>
> --
> Keith Thompson (The_Other_Keith) <ks...@mib.org>
> [...]
> "We must do something. This is something. Therefore, we must do this."
> -- Antony Jay and Jonathan Lynn, "Yes Minister"


Thanks for help. Maybe I'm not making myself clear. vfscanf() seems to
be a GNU extension, however, I'm under win32. I've searched MSDN and
find solutions like following:

void vfscanf_c( FILE* fp, u_int argNum, const char *format, ...)
{

#define SCANF_MAX_ARGS 10
va_list arglist;
void *args[SCANF_MAX_ARGS];
u_int numScanned;

if( argNum > SCANF_MAX_ARGS )
throw "Too much args!";

va_start( arglist, format );
{
for ( u_int i=0; i<argNum; i++ )
{
args[i] = va_arg( arglist, void* );
}
}
va_end( arglist );

numScanned = fscanfWrapper( fp, argNum, format, args );

if( numScanned != argNum )
throw "Fscanf args Error!";

}

u_int fscanfWrapper( FILE* fp, u_int argNum, const char*format, void**
p )
{
#define ADD_ARGS_1 p[0]
#define ADD_ARGS_2 ADD_ARGS_1, p[1]
#define ADD_ARGS_3 ADD_ARGS_2, p[2]
#define ADD_ARGS_4 ADD_ARGS_3, p[3]
#define ADD_ARGS_5 ADD_ARGS_4, p[4]
#define ADD_ARGS_6 ADD_ARGS_5, p[5]
#define ADD_ARGS_7 ADD_ARGS_6, p[6]
#define ADD_ARGS_8 ADD_ARGS_7, p[7]
#define ADD_ARGS_9 ADD_ARGS_8, p[8]
#define ADD_ARGS_10 ADD_ARGS_9, p[9]

switch ( argNum )
{
case 0: return 0;
case 1: return fscanf( fp, format, ADD_ARGS_1 );
case 2: return fscanf( fp, format, ADD_ARGS_2 );
case 3: return fscanf( fp, format, ADD_ARGS_3 );
case 4: return fscanf( fp, format, ADD_ARGS_4 );
case 5: return fscanf( fp, format, ADD_ARGS_5 );
case 6: return fscanf( fp, format, ADD_ARGS_6 );
case 7: return fscanf( fp, format, ADD_ARGS_7 );
case 8: return fscanf( fp, format, ADD_ARGS_8 );
case 9: return fscanf( fp, format, ADD_ARGS_9 );
case 10: return fscanf( fp, format, ADD_ARGS_10 );
default:
throw "Too much args in fscanf!";
return -1;
}
}

There're some C++ characteristic there, let's neglectthem and just
focus on the method. I've run some test and find it just fine.

James Kuyper 01-07-2008 12:52 PM

Re: Question about va_list
 
Fred wrote:
....
> Thanks for help. Maybe I'm not making myself clear. vfscanf() seems to
> be a GNU extension, however, I'm under win32. I've searched MSDN and
> find solutions like following:


No, vfscanf() is part of the C standard library. I'm not sure whether it
was part of C90, but it's specified in section 7.19.6.9 of the current
standard.

Ben Bacarisse 01-07-2008 01:07 PM

Re: Question about va_list
 
James Kuyper <jameskuyper@verizon.net> writes:

> Fred wrote:
> ...
>> Thanks for help. Maybe I'm not making myself clear. vfscanf() seems to
>> be a GNU extension, however, I'm under win32. I've searched MSDN and
>> find solutions like following

>
> No, vfscanf() is part of the C standard library. I'm not sure whether it
> was part of C90, but it's specified in section 7.19.6.9 of the current
> standard.


It was not in C90 (the vprintf family were, but for some reason not
the vscanf family) and so it is probably not available with MS
compilers (the OP seems to MS-based).

--
Ben.

Ben Bacarisse 01-07-2008 01:28 PM

Re: Question about va_list
 
Fred <hn.ft.pris@gmail.com> writes:

> On Jan 7, 2:57 pm, Keith Thompson <ks...@mib.org> wrote:
>> Fred <hn.ft.p...@gmail.com> writes:
>> > I've got following program encapsuled fscanf, however, it doesn't
>> > work.

<snip>
>> > int vsscanf( FILE* fp, const char *fmt, ... )
>> > {
>> > va_list arglist;
>> > va_start( arglist, fmt );
>> > return fscanf(fp, fmt, arglist);
>> > }

<snip>
>> You're probably looking for vfscanf(). What you're trying to do in
>> this program is equivalent to just calling fscanf() directly, but
>> presumably you're going to do some more stuff in your vsscanf().

<snip>
>> --
>> Keith Thompson (The_Other_Keith) <ks...@mib.org>
>> [...]
>> "We must do something. This is something. Therefore, we must do this."
>> -- Antony Jay and Jonathan Lynn, "Yes Minister"


Please don't quote sigs (the bits after the "-- "). In fact, try to
remove as much quoted text as possible to leave a message that stands
on its own (for example, I've left the gist of your question and Keith
Thompson's key point intact but removed as much of the rest as I can).

> Thanks for help. Maybe I'm not making myself clear. vfscanf() seems to
> be a GNU extension, however, I'm under win32.


No, vfscanf is standard C. It is, however, only in the latest
standard (C99) and MS have decided not to implement this. One
solution is to switch to a compiler and C library that supports it.
If that is too troublesome, you could try to find a C99 library (or at
least one with vfscanf) that works with your compiler. Posting in an
MS programming group might help you find one.

> I've searched MSDN and find solutions like following
>
> void vfscanf_c( FILE* fp, u_int argNum, const char *format, ...)
> {
>
> #define SCANF_MAX_ARGS 10
> va_list arglist;
> void *args[SCANF_MAX_ARGS];
> u_int numScanned;
>
> if( argNum > SCANF_MAX_ARGS )
> throw "Too much args!";
>
> va_start( arglist, format );
> {
> for ( u_int i=0; i<argNum; i++ )
> {
> args[i] = va_arg( arglist, void* );
> }
> }
> va_end( arglist );
>
> numScanned = fscanfWrapper( fp, argNum, format, args );
>
> if( numScanned != argNum )
> throw "Fscanf args Error!";
>
> }
>
> u_int fscanfWrapper( FILE* fp, u_int argNum, const char*format, void**
> p )
> {
> #define ADD_ARGS_1 p[0]
> #define ADD_ARGS_2 ADD_ARGS_1, p[1]
> #define ADD_ARGS_3 ADD_ARGS_2, p[2]
> #define ADD_ARGS_4 ADD_ARGS_3, p[3]
> #define ADD_ARGS_5 ADD_ARGS_4, p[4]
> #define ADD_ARGS_6 ADD_ARGS_5, p[5]
> #define ADD_ARGS_7 ADD_ARGS_6, p[6]
> #define ADD_ARGS_8 ADD_ARGS_7, p[7]
> #define ADD_ARGS_9 ADD_ARGS_8, p[8]
> #define ADD_ARGS_10 ADD_ARGS_9, p[9]
>
> switch ( argNum )
> {
> case 0: return 0;
> case 1: return fscanf( fp, format, ADD_ARGS_1 );
> case 2: return fscanf( fp, format, ADD_ARGS_2 );
> case 3: return fscanf( fp, format, ADD_ARGS_3 );
> case 4: return fscanf( fp, format, ADD_ARGS_4 );
> case 5: return fscanf( fp, format, ADD_ARGS_5 );
> case 6: return fscanf( fp, format, ADD_ARGS_6 );
> case 7: return fscanf( fp, format, ADD_ARGS_7 );
> case 8: return fscanf( fp, format, ADD_ARGS_8 );
> case 9: return fscanf( fp, format, ADD_ARGS_9 );
> case 10: return fscanf( fp, format, ADD_ARGS_10 );
> default:
> throw "Too much args in fscanf!";
> return -1;
> }
> }
>
> There're some C++ characteristic there, let's neglectthem and just
> focus on the method. I've run some test and find it just fine.


Yuck. If it suits you, then fine, but it would break on at least one
machine I've used.

--
Ben.

J. J. Farrell 01-07-2008 04:23 PM

Re: Question about va_list
 
Fred wrote:
> On Jan 7, 2:57 pm, Keith Thompson <ks...@mib.org> wrote:
>> Fred <hn.ft.p...@gmail.com> writes:
>>> I've got following program encapsuled fscanf, however, it doesn't
>>> work.

>> You say "it doesn't work". How exactly doesn't it work? What results
>> did you get, what did you expect, and how did they differ?
>>
>> Recommended reading:
>> <http://www.catb.org/~esr/faqs/smart-questions.html>.
>>
>>> I'm sure that the content format in "a.txt" is OK, the content would
>>> be correctly read if using fscanf directly, what's wrong with my
>>> program? Thanks for help!

>> It's difficult to be certain, because you didn't show us your complete
>> program. Presumably you have #include directives for at least
>> <stdio.h> and <stdarg.h>. You *should* also have #includes for
>> <string.h> and <stdlib.h>.
>>
>>> int vsscanf( FILE* fp, const char *fmt, ... )
>>> {
>>> va_list arglist;
>>> va_start( arglist, fmt );
>>> return fscanf(fp, fmt, arglist);
>>> }
>>> int main()

>> Slightly better: "int main(void)".
>>
>>> {
>>> FILE* fp = fopen( "C:\\a.txt", "r" );
>>> if( fp == 0 )
>>> {
>>> printf( "%s\n", "Open File Error!" );
>>> exit(-1);

>> Minor quibble: "exit(-1)" is non-portable. The only portable
>> arguments to exit() are 0, EXIT_SUCCESS, and EXIT_FAILURE.
>>
>>> }
>>> char buffer[128];
>>> char buffer2[128];

>> You never use this.
>>
>>> memset( buffer, 0, 128 );

>> Why the memset?
>>
>>> vsscanf( fp, "%s\n", buffer );
>>> printf( "%s\n", buffer );
>>> return 1;

>> See "Minor quibble" above. Why not "return 0;"?
>>
>>> }

>> The real problem is that you're trying to pass a va_list to fscanf().
>> In this particular call, the format argument is "%s\n", which means
>> the third argument should be a char*, not a va_list.
>>
>> You're probably looking for vfscanf(). What you're trying to do in
>> this program is equivalent to just calling fscanf() directly, but
>> presumably you're going to do some more stuff in your vsscanf().
>>
>> Incidentally, fscanf() with a "%s" format is potentially dangerous,
>> unless you can be sure that the input won't overflow your buffer.
>> (scanf() with a "%s" format is even more dangerous, since you
>> generally don't have complete control over what will appear on stdin.)

>
> Thanks for help. Maybe I'm not making myself clear. vfscanf() seems to
> be a GNU extension, however, I'm under win32. I've searched MSDN and
> find solutions like following:
>
> void vfscanf_c( FILE* fp, u_int argNum, const char *format, ...)
> {
>
> #define SCANF_MAX_ARGS 10
> va_list arglist;
> void *args[SCANF_MAX_ARGS];
> u_int numScanned;
>
> if( argNum > SCANF_MAX_ARGS )
> throw "Too much args!";
>
> va_start( arglist, format );
> {
> for ( u_int i=0; i<argNum; i++ )
> {
> args[i] = va_arg( arglist, void* );
> }
> }
> va_end( arglist );
>
> numScanned = fscanfWrapper( fp, argNum, format, args );
>
> if( numScanned != argNum )
> throw "Fscanf args Error!";
>
> }
>
> u_int fscanfWrapper( FILE* fp, u_int argNum, const char*format, void**
> p )
> {
> #define ADD_ARGS_1 p[0]
> #define ADD_ARGS_2 ADD_ARGS_1, p[1]
> #define ADD_ARGS_3 ADD_ARGS_2, p[2]
> #define ADD_ARGS_4 ADD_ARGS_3, p[3]
> #define ADD_ARGS_5 ADD_ARGS_4, p[4]
> #define ADD_ARGS_6 ADD_ARGS_5, p[5]
> #define ADD_ARGS_7 ADD_ARGS_6, p[6]
> #define ADD_ARGS_8 ADD_ARGS_7, p[7]
> #define ADD_ARGS_9 ADD_ARGS_8, p[8]
> #define ADD_ARGS_10 ADD_ARGS_9, p[9]
>
> switch ( argNum )
> {
> case 0: return 0;
> case 1: return fscanf( fp, format, ADD_ARGS_1 );
> case 2: return fscanf( fp, format, ADD_ARGS_2 );
> case 3: return fscanf( fp, format, ADD_ARGS_3 );
> case 4: return fscanf( fp, format, ADD_ARGS_4 );
> case 5: return fscanf( fp, format, ADD_ARGS_5 );
> case 6: return fscanf( fp, format, ADD_ARGS_6 );
> case 7: return fscanf( fp, format, ADD_ARGS_7 );
> case 8: return fscanf( fp, format, ADD_ARGS_8 );
> case 9: return fscanf( fp, format, ADD_ARGS_9 );
> case 10: return fscanf( fp, format, ADD_ARGS_10 );
> default:
> throw "Too much args in fscanf!";
> return -1;
> }
> }
>
> There're some C++ characteristic there, let's neglectthem and just
> focus on the method. I've run some test and find it just fine.


I'm confused. You've got some example C++ code which can be trivially
translated into C. You say that you find it just fine. In that case, why
don't you use it?

What was wrong with Keith's answer to your original question?

CBFalconer 01-07-2008 10:12 PM

Re: Question about va_list
 
Fred wrote:
>

.... snip ...
>
> Thanks for help. Maybe I'm not making myself clear. vfscanf()
> seems to be a GNU extension, however, I'm under win32. I've
> searched MSDN and find solutions like following


No, vfscanf is standard C. If missing on your compiler, the
compiler has failed. Complain to the compiler manufacturer. The
following is from N869:

7.19.6.9 The vfscanf function

Synopsis

[#1]
#include <stdarg.h>
#include <stdio.h>
int vfscanf(FILE * restrict stream,
const char * restrict format,
va_list arg);
Description

[#2] The vfscanf function is equivalent to fscanf, with the
variable argument list replaced by arg, which shall have
been initialized by the va_start macro (and possibly
subsequent va_arg calls). The vfscanf function does not
invoke the va_end macro.231)

Returns

[#3] The vfscanf function returns the value of the macro EOF
if an input failure occurs before any conversion.
Otherwise, the vfscanf 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.

____________________

231As the functions vfprintf, vfscanf, vprintf, vscanf,
vsnprintf, vsprintf, and vsscanf invoke the va_arg macro,
the value of arg after the return is indeterminate.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com



All times are GMT. The time now is 02:14 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.