1. prototypes using the ellipsis notation for variable argument lists
don't match varargs-style function definitions;
2. because of the built-in semicolon, prototypes can't contain va_dcl.
I'm a bit resigned to having missing prototype warnings for the module
that contains the function definitions. I'd still like to have
prototypes in all the other modules, and the ellipsis notation
seems to be the only way to do this.
How dangerous is it to call functions declared externally using the
ellipsis notation, but defined using va_dcl? May a conforming implement-
ation assume that functions with ellipsis prototypes use <stdarg.h>-style
arguments and not <varargs.h>-style?
--
Scott D. Eberline sco...@locus.com or lcc!scotte
As you have discovered, there is no correct way to use prototypes for
<varargs.h>-style variadic functions (when they are supported at all).
You ought to simply use the empty-parenthesis (old style) form of declaration
for such functions.
By the way, I take exception to the implementation warning you that no
prototypes exists, unles you have specifically asked for that check.
The C standard does not require that prototypes be used.
>How dangerous is it to call functions declared externally using the
>ellipsis notation, but defined using va_dcl? May a conforming implement-
>ation assume that functions with ellipsis prototypes use <stdarg.h>-style
>arguments and not <varargs.h>-style?
The answer to the second question is "Certainly, and indeed it is likely."
Therefore the answer to the first question is that it is not a good idea.
>By the way, I take exception to the implementation warning you that no
>prototypes exists, unles you have specifically asked for that check.
>The C standard does not require that prototypes be used.
But an implementation is allowed to issue spurious diagnostics.
Presumably spurious diagnostics can convey useful information :-)
We agree that in a quality implementation, there would be an option to
turn useful spurious diagnostics on or off. But as for which setting
to use for the default, what is high quality to one person seems to be
low quality to another person.
--
Norman Diamond dia...@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.
Permission is granted to feel this signature, but not to look at it.
OK, so you want your code to work with ANSI and non-ansi compilers.
Why not accomodate both in your source. That's what the predefined
__STDC__ macro is for.
Declarations:
#ifdef __STDC__
void foo(char *format, ...);
#else
void foo();
#endif
Definitions:
#ifdef __STDC__
void foo(char *format, ...)
#else
void foo(format, va_alist) char *format; va_dcl
#endif
{
va_list ap;
#ifdef __STDC__
va_start(ap,format);
#else
va_start(ap);
#endif
[ ... rest of stuff the same ... ]
}
>I'm a bit resigned to having missing prototype warnings for the module
>that contains the function definitions. I'd still like to have
>prototypes in all the other modules, and the ellipsis notation
>seems to be the only way to do this.
It's nice to have a compiler which requires having prototypes if you
want them. Of course, this isn't required by ANSI.
>How dangerous is it to call functions declared externally using the
>ellipsis notation, but defined using va_dcl?
Very. If a stdarg prototype is visible at a call site, it allows the
compiler to generate a different calling sequence. For example, if a
compiler normally passes arguments in registers, it may choose to just
load them on the data stack instead when it sees a stdarg call site
(an optimization; otherwise it would just have to store down the
registers on function entry). Since it can depend on the definition of
the function to also have the stdarg notation, it will know how to
"pick up" the arguements in the function body.
>May a conforming implement-
>ation assume that functions with ellipsis prototypes use <stdarg.h>-style
>arguments and not <varargs.h>-style?
Well, it may assume that an ellipsis prototype was visible at every call
site of "foo" if "foo" is defined using the ellipsis notation.
>--
>Scott D. Eberline sco...@locus.com or lcc!scotte
-Mark Hall (smart mailer): mark...@pyrps5.pyramid.com
(uucp paths): {uunet|ames|decwrl|sun|seismo}!pyramid!markhall
The above form for <varargs.h> usage is wrong. The documentation, and some
implementations, REQUIRE you to declare the function as:
void foo(va_alist) va_dcl
and then pick off the fixed arguments using va_arg:
char *format;
format = va_arg(ap,char*);
Any other usage is non-portable (as portable as you can be using varargs.h,
that is. :-) )
Tony Hansen
han...@pegasus.att.com, to...@attmail.com
att!pegasus!hansen, attmail!tony
In article <1991Jun18....@cbnewsk.att.com> han...@pegasus.att.com
(Tony L. Hansen) writes:
>The above form for <varargs.h> usage is wrong. ...
This is correct; however, I have used the above, and continue to use it,
in 4BSD code, with the excuse that:
a) it is far clearer; and
b) if your varargs does not handle it, you can probably obtain an ANSI C
implementation and use the __STDC__ code anyway.
In other words, we are not willing to bend over backwards (for compatibility)
until it hurts, only until it is mildly uncomfortable. :-)
Chris
--
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA Domain: to...@ee.lbl.gov
But surely it's not appreciably harder, for the few uses of varargs
functions, to type the always correct
void foo(va_alist)
va_dcl
{
char *format;
...
format = va_arg(ap, char *);
...
}
instead of the sometimes incorrect
void foo(format, va_alist)
char *format;
va_dcl
{
...
...
}
In article <16...@smoke.brl.mil> gw...@smoke.brl.mil (Doug Gwyn) writes:
>But surely it's not appreciably harder, for the few uses of varargs
>functions, to type the always correct
[and vertically compressed and reformatted a bit by me]
> void foo(va_alist) va_dcl {
> char *format; ...
> format = va_arg(ap, char *);
> ...
> }
>instead of the sometimes incorrect
> void foo(format, va_alist) char *format; va_dcl {
> ...
> }
No. However, combine this with the ANSI C version:
int
#ifdef __STDC__
abc(int level, int type, struct foo *obj, const char *fmt, ...)
#else
abc(va_alist)
va_dcl
#endif
{
#ifndef __STDC__
int level;
int type;
struct foo *obj;
char *fmt;
#endif
int ret;
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
level = va_arg(ap, int);
type = va_arg(ap, int);
obj = va_arg(ap, struct foo *);
fmt = va_arg(ap, char *);
#endif
ret = vabc(level, type, obj, fmt, ap);
va_end(ap);
return (ret);
}
Now compare this with the easier (but incorrect unless __STDC__) code:
int
#ifdef __STDC__
abc(int level, int type, struct foo *obj, const char *fmt, ...)
#else
abc(level, type, obj, fmt, va_alist)
int level;
int type;
struct foo *obj;
char *fmt;
va_dcl
#endif
{
int ret;
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
ret = vabc(level, type, obj, fmt, ap);
va_end(ap);
return (ret);
}
This saves six lines (24 vs 30; 20% less) and moves the argument matching
maintenance together where it is clearer. (Suppose, for instance, the
`type' argument is split into two arguments, or is merged into the
`foo' object.) Now multiply this by a dozen varargs functions spread
over a few hundred files. We (Keith Bostic and I, at least) would
rather deal with the second (technically broken) version, due to easier
maintenance, and tell those who have trouble with it to find an ANSI C
compiler (and/or port GCC).
You could also suggest that the necessary change to the code to attain
"portable" usage of <varargs.h> is straightforward, and let them do the
extra work if and when the occasion arises.