va_list: how to produce warnings at compile time if calledincorrectly?

F

Felix Kater

Hi,

I would like to write a variadic function f(const int MY_TYPE_X, ...) were MY_TYPE_X is not the amount of arguments but an index representing both: the amount of args and their type.

So, for each MY_TYPE_X, it should be allowed to call f only as if it were either f1, f2 or f3:

void f1(MY_TYPE_0, int){ /* ... */ }
void f2(MY_TYPE_1, int, void*, char*){ /* ... */ }
void f3(MY_TYPE_2, long, long){ /* ... */}

My question: Can I make the compiler produce warnings like with printf called incorrectly? E.g., this should produce a warning:

f(MY_TYPE_0, "a string", 99);

Felix
 
F

Flash Gordon

Felix said:
Hi,

I would like to write a variadic function f(const int MY_TYPE_X, ...) were MY_TYPE_X is not the amount of arguments but an index representing both: the amount of args and their type.

So, for each MY_TYPE_X, it should be allowed to call f only as if it were either f1, f2 or f3:

void f1(MY_TYPE_0, int){ /* ... */ }
void f2(MY_TYPE_1, int, void*, char*){ /* ... */ }
void f3(MY_TYPE_2, long, long){ /* ... */}

My question: Can I make the compiler produce warnings like with printf called incorrectly? E.g., this should produce a warning:

f(MY_TYPE_0, "a string", 99);

I would say that this was implementation specific only I doubt that you
can do it with any implementation. Just on the off chance I am wrong and
you can, ask on a group dedicated to your implementation.
 
E

Eric Sosman

Felix Kater wrote On 05/16/06 09:30,:
Hi,

I would like to write a variadic function f(const int MY_TYPE_X, ...) were MY_TYPE_X is not the amount of arguments but an index representing both: the amount of args and their type.

So, for each MY_TYPE_X, it should be allowed to call f only as if it were either f1, f2 or f3:

void f1(MY_TYPE_0, int){ /* ... */ }
void f2(MY_TYPE_1, int, void*, char*){ /* ... */ }
void f3(MY_TYPE_2, long, long){ /* ... */}

My question: Can I make the compiler produce warnings like with printf called incorrectly? E.g., this should produce a warning:

f(MY_TYPE_0, "a string", 99);

The language itself has no way to restrict the "..."
arguments. You cannot even say "They must all be ints"
or "They must come in int/char* pairs." The compiler you
use may have extra-linquistic features to allow this, but
the C language can't do it unaided.

My question, though: If you've got f1(),f2(),f3()
with known, fixed-length argument "signatures," why do
you want to somehow collapse them all into a single
variadic function f()? What does it gain you (you've
already discovered some of what it loses)?
 
F

Felix Kater

The language itself has no way to restrict the "..."
arguments.

I wonder how printf does that? If I do

long my_long=0;
printf("%d",my_long);

I get a warning from gcc that an int was expected.
So, shouldn't it be possible somehow?

Felix
 
F

Felix Kater

My question, though: If you've got f1(),f2(),f3()
with known, fixed-length argument "signatures," why do
you want to somehow collapse them all into a single
variadic function f()? What does it gain you (you've
already discovered some of what it loses)?

My idea is to create a general function f which first does some general
things (according on groups of MY_TYPE_X passed as the first arg) and
then calls the appropriate callback to the other arguments are passed.
So, in other words I'd like to help myself and other developers in my
project in the way that those "general things" are done in any case
so we can concentrate on the callbacks. One simple example of these
general things is to first check in each new public function if the
module was initialized.

Felix
 
V

Vladimir Oka

Felix said:
I wonder how printf does that? If I do

long my_long=0;
printf("%d",my_long);

I get a warning from gcc that an int was expected.
So, shouldn't it be possible somehow?

The warning is courtesy of GCC. It is not required by the standard.
 
F

Flash Gordon

Felix said:
I wonder how printf does that? If I do

long my_long=0;
printf("%d",my_long);

I get a warning from gcc that an int was expected.

gcc has a parser for the printf built in to it.
So, shouldn't it be possible somehow?

How on earth is it going to be possible in the general case? I could
write my own printf like function that uses different format specifiers,
being indicated by a different character, and I would have to be able to
describe that to the compiler. I could also have a function where every
other parameter tells the function what type the next parameter is, but
the encoding of the type information changes dependant on the type of
the last but one parameter pair.

Can you really come up with a generic method to describe all possible
ways that the parameter types could be determined? Given that there are
people like me who can be exceedingly devious?

The final word on this is that the C standard, the document that
actually defined the C programming language, does not specify any
mechanism to do what you want, therefore even if it was very simple to
do (as in some cases with printf) then there would *still* be no way to
do it as far as C is concerned.

As I said in another post, if you want to know if there is any way to
get your compiler to do any checking for you as in a group dedicated to it.
 
E

Eric Sosman

Felix Kater wrote On 05/16/06 11:11,:
I wonder how printf does that? If I do

long my_long=0;
printf("%d",my_long);

I get a warning from gcc that an int was expected.
So, shouldn't it be possible somehow?

That's one of those "extra-linguistic features" I
mentioned. gcc has a gcc-specific way of checking for
disagreement between printf-like and scanf-like format
strings and the arguments provided to match them. It
may be possible to get gcc to make other kinds of checks
as well; consult the gcc documentation.

But all these things are specific to gcc; the C
language itself has no way of expressing any restrictions
on the "..." arguments. Since the restrictions cannot
even be expressed, they cannot be enforced -- without,
as I said, going outside the language and dealing directly
with the compiler, whether it's gcc or something else.
 
A

Andrew Poelstra

I wonder how printf does that? If I do

long my_long=0;
printf("%d",my_long);

I get a warning from gcc that an int was expected.
So, shouldn't it be possible somehow?
Using gcc-specific extensions, it is certainly possible. I get
the illusion that printf is built right into the compiler from
some of the errors it gives me.
 
E

Eric Sosman

Felix Kater wrote On 05/16/06 11:22,:
My idea is to create a general function f which first does some general
things (according on groups of MY_TYPE_X passed as the first arg) and
then calls the appropriate callback to the other arguments are passed.
So, in other words I'd like to help myself and other developers in my
project in the way that those "general things" are done in any case
so we can concentrate on the callbacks. One simple example of these
general things is to first check in each new public function if the
module was initialized.

It seems to me it would be less burdensome to put the
initialization checks into f1(),f2(),f3() than to require
the user to write f(please_call_f1_for_me, f1_arguments).
 
J

John Devereux

Eric Sosman said:
Felix Kater wrote On 05/16/06 11:11,:

That's one of those "extra-linguistic features" I
mentioned. gcc has a gcc-specific way of checking for
disagreement between printf-like and scanf-like format
strings and the arguments provided to match them. It
may be possible to get gcc to make other kinds of checks
as well; consult the gcc documentation.

I don't think it is gcc-specific, in that any compiler could in
principle do this for printf (and sprintf, scanf etc) because the
format string meaning is defined by the C standard. Same thing with
replacing printf() calls with puts(), where these would be equivalent
(which gcc also does). gcc is allowed to assume that the standard
library functions behave according to the standard, and it does this
in several areas.

But for user-written functions it has no way of knowing, within
standard C, what the format string is supposed to mean.
 
E

Eric Sosman

John Devereux wrote On 05/16/06 11:53,:
I don't think it is gcc-specific, in that any compiler could in
principle do this for printf (and sprintf, scanf etc) because the
format string meaning is defined by the C standard. Same thing with
replacing printf() calls with puts(), where these would be equivalent
(which gcc also does). gcc is allowed to assume that the standard
library functions behave according to the standard, and it does this
in several areas.

Thanks for the correction. I ought to have said that
the mechanism gcc actually uses for these checks is a gcc-
specific mechanism, not that the checking itself has to be
gcc-specific.
But for user-written functions it has no way of knowing, within
standard C, what the format string is supposed to mean.

As it happens, gcc's mechanism can be used to tag user-
written functions, too. If you want to write a logging
function that takes a printf-like format string and matching
arguments, you can get gcc to check it for you. I haven't
studied the gcc annotations enough to tell whether they're
easily extensible to the kinds of checks the O.P. wants, though.
 
F

Felix Kater

It seems to me it would be less burdensome to put the
initialization checks into f1(),f2(),f3() than to require
the user to write f(please_call_f1_for_me, f1_arguments).

Hm. Initialization checks were just an example. I have to keep an eye
on much more like module dependencies, its actual runlevels an so on.

So, let me get it this way then: It's not only about keeping the
interface (more or less) easy to use for the client programmer. But for
larger projects it's not less important to keep the code simple for
changes an extensions to the developers of the project. In our case it
got hard to change anything since the developers have to think of too
many things before being able to change anything. A good redesign is my
motivation--letting the user do some more overhead is ok if this makes
it possible for the developers to keep on coding.

Of course, I don't want to make things more complicated than necessary.

I was thinking of doing things like this

general_f(create_new_struct_of_same_type_f1( int i, long l))
general_f(create_new_struct_of_same_type_f2( void*, char*))

But to have this convenient to the client, general_f should detroy
the structs internally--but what with return values, then? ...I am
still not convinced of it all.

Felix
 

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

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top