[comp.std.c] <varargs.h> vs. function prototypes

scotte@locus.com (Scott D. Eberline) (06/13/91)

For software that may potentially be ported to platforms not yet
ANSI-compliant, some functions taking variable arguments are
defined using <varargs.h> instead of <stdarg.h>.  I would like
to declare full prototypes for these to avoid compiler warnings
about missing prototypes.  In the module in which these functions
are defined, this doesn't seem to be possible:

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			scotte@locus.com  or  lcc!scotte

gwyn@smoke.brl.mil (Doug Gwyn) (06/13/91)

In article <25353@oolong.la.locus.com> scotte@locus.com (Scott D. Eberline) writes:
>I'm a bit resigned to having missing prototype warnings for the module
>that contains the function definitions.

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.

diamond@jit533.swstokyo.dec.com (Norman Diamond) (06/14/91)

In article <16405@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:

>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       diamond@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.

markhall@pyrps5.pyramid.com (Mark Hall) (06/15/91)

In article <25353@oolong.la.locus.com> scotte@locus.com (Scott D. Eberline) writes:
>For software that may potentially be ported to platforms not yet
>ANSI-compliant, some functions taking variable arguments are
>defined using <varargs.h> instead of <stdarg.h>.  I would like
>to declare full prototypes for these to avoid compiler warnings
>about missing prototypes.  In the module in which these functions
>are defined, this doesn't seem to be possible:

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			scotte@locus.com  or  lcc!scotte

-Mark Hall (smart mailer): markhall@pyrps5.pyramid.com
	   (uucp paths): {uunet|ames|decwrl|sun|seismo}!pyramid!markhall

hansen@pegasus.att.com (Tony L. Hansen) (06/18/91)

< From: markhall@pyrps5.pyramid.com (Mark Hall)
<	#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 ... ]
<	}

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
			    hansen@pegasus.att.com, tony@attmail.com
				att!pegasus!hansen, attmail!tony

torek@elf.ee.lbl.gov (Chris Torek) (06/19/91)

>In article <159364@pyramid.pyramid.com> markhall@pyrps5.pyramid.com
>(Mark Hall) writes:
>>	#ifdef __STDC__
>>	void foo(char *format, ...)
>>	#else
>>	void foo(format, va_alist) char *format; va_dcl
>>	#endif
[and on from there]

In article <1991Jun18.145823.2512@cbnewsk.att.com> hansen@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:	torek@ee.lbl.gov

gwyn@smoke.brl.mil (Doug Gwyn) (06/19/91)

In article <14423@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
>In other words, we are not willing to bend over backwards (for compatibility)
>until it hurts, only until it is mildly uncomfortable. :-)


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
		{
		...
		...
		}

torek@elf.ee.lbl.gov (Chris Torek) (06/21/91)

>In article <14423@dog.ee.lbl.gov> I wrote:
>>In other words, we are not willing to bend over backwards (for compatibility)
>>until it hurts, only until it is mildly uncomfortable. :-)

In article <16456@smoke.brl.mil> gwyn@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).
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

gwyn@smoke.brl.mil (Doug Gwyn) (06/21/91)

In article <14532@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
>... 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.