Question about va_list

F

Fred

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

Ark Khasin

Fred said:
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
 
K

Keith Thompson

Fred said:
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:
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
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.)
 
F

Fred

Fred said:
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:
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
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) <[email protected]>
[...]
"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$B!'(B

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 = 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.
 
J

James Kuyper

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$B!'(B

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.
 
B

Ben Bacarisse

James Kuyper said:
Fred wrote:
...

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).
 
B

Ben Bacarisse

Fred said:
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().
--
Keith Thompson (The_Other_Keith) <[email protected]>
[...]
"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 = 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.
 
J

J. J. Farrell

Fred said:
Fred said:
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:
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
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$B!'(B

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 = 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?
 
C

CBFalconer

Fred said:
.... 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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

question about va_list 1
URGENT 1
Adding adressing of IPv6 to program 1
[va_list *] Is this legal ? 33
Help with EXT3 Filesystem work 1
dynamic construction of va_list 1
C pipe 1
Cgi and file access 8

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top