[comp.std.c] prototypes required ?

jeff@oakhill.UUCP (Jeff Enderwick) (10/16/90)

This has probably come up before ...

Is it legal for a compilation system to require prototypes when stdarg
functions are used ? It valid for the compiler to require you to include
the prototype:

	int printf ( const char*, ... );

before making the call:

	 printf ( "hello %d worlds\n", 5 );

? If not, where does the ANSI spec say so ?

	Jeff Enderwick
	DSP Compiler Development
	Motorola, Inc.
	(512) 891-3388

	cs.utexas.edu!oakhill!otis!jeff

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/17/90)

In article <4026@otis.oakhill.UUCP> jeff@oakhill.UUCP (Jeff Enderwick) writes:
>Is it legal for a compilation system to require prototypes when stdarg
>functions are used ? It valid for the compiler to require you to include
>the prototype:
>	int printf ( const char*, ... );
>before making the call:
>	 printf ( "hello %d worlds\n", 5 );

Yes, you definitely must have a prototype in scope before calling a
variable-argument function in a strictly conforming program.

For printf(), you should #include <stdio.h> instead of declaring it
yourself.  You might get better results that way in some implementations.

volpe@underdog.crd.ge.com (Christopher R Volpe) (10/17/90)

In article <14164@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
|>In article <4026@otis.oakhill.UUCP> jeff@oakhill.UUCP (Jeff Enderwick)
writes:
|>>Is it legal for a compilation system to require prototypes when stdarg
|>>functions are used ? It valid for the compiler to require you to include
|>>the prototype:
|>>	int printf ( const char*, ... );
|>>before making the call:
|>>	 printf ( "hello %d worlds\n", 5 );
|>
|>Yes, you definitely must have a prototype in scope before calling a
|>variable-argument function in a strictly conforming program.

Two questions:
  1) Can you point me to a reference in the standard that says that
     old-style declarations are insufficient for a variable argument
     function in a strictly conforming program? Or are old style declarations
     insufficient for ANY kind of function in a strictly conforming
     program?

  2) Are you sure you answered the question he asked? Jeff asked if
     it is valid for the compiler to REQUIRE YOU TO include the
     prototype. To me, "require you to" means "refuse to generate
     code unless you...". That's a different issue. Unless a program
     violates a syntax rule or a semantic constraint, the compiler
     can at most issue a warning but must still generate code. I
     believe (please correct me if I'm wrong) that a program can
     fail to be strictly conforming (and even fail to be conforming)
     without violating any semantic constraints. Is this correct?
             
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

pds@lemming.webo.dg.com (Paul D. Smith) (10/17/90)

[] Is it legal for a compilation system to require prototypes when stdarg
[] functions are used ?

The thing you need to remember is that, in the definition of the
stdarg package, each function *must* have at least the first argument
defined; i.e., you cannot declare a function as:

    int my_func( ... );

You must have at least one argument (see K&R II, Sec B7, p 254).  So,
if you are going to add the "..." construct you must declare a
prototype for the first argument.

I see no reason you could just not prototype anything, however:

    int printf();

This should cause no problems.

--

                                                                paul
-----
 ------------------------------------------------------------------
| Paul D. Smith                          | pds@lemming.webo.dg.com |
| Data General Corp.                     |                         |
| Network Services Development           |   "Pretty Damn S..."    |
| Open Network Applications Department   |                         |
 ------------------------------------------------------------------

Christopher-Vance@adfa.oz.au (10/18/90)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
| Yes, you definitely must have a prototype in scope before calling a
| variable-argument function in a strictly conforming program.

Which means that gcc -ansi on a Pyramid cannot compile such a thing. I am
informed that the only way to make printf work is to *omit* the prototype.

karl@haddock.ima.isc.com (Karl Heuer) (10/18/90)

In article <1964@ccadfa.adfa.oz.au> Christopher-Vance@adfa.oz.au writes:
>gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>| Yes, you definitely must have a prototype in scope [for printf()]
>
>Which means that gcc -ansi on a Pyramid cannot compile such a thing. I am
>informed that the only way to make printf work is to *omit* the prototype.

Presumably this is caused by having to link with the native implementation of
printf(), and hence will be fixed when the FSF releases the GNU library.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint

diamond@tkou02.enet.dec.com (diamond@tkovoa) (10/18/90)

In article <12826@crdgw1.crd.ge.com> volpe@underdog.crd.ge.com (Christopher R Volpe) writes:

>  1) Can you point me to a reference in the standard that says that
>     old-style declarations are insufficient for a variable argument
>     function in a strictly conforming program?

Section 3.5.4.3 plus section 3.7.1 together do this.
Section 3.5.4.3, semantics, sixth paragraph:
  "If one type has a parameter list and the other type is specified by
  a function declarator that is not part of a function definition and
  that contains an empty identifier list, the parameter list shall not
  have an ellipsis terminator..."
  Thus, if there is a non-defining declaration of printf without a
  prototype, then all definitions and declarations of printf that
  do have prototypes must not have an ellipsis.
Section 3.7.1, semantics, second paragraph:
  "If a function that accepts a variable number of arguments is defined
  without a parameter list that ends with the ellipsis notation, the
  behavior is undefined."
  Thus, if printf's implementation is defined in ANSI C, it must be defined
  with a prototype that ends with an ellipsis.

If your <stdio.h> does not declare printf, and your library provides a
definition of printf that was not coded in ANSI C, then it seems that a
loophole allows you to make your own extern declaration of printf without
a proper prototype.  I would not suggest depending on this.

I didn't check if there's another loophole that might permit printf
to be called (with defined results) without any declaration at all, but 
it doesn't seem likely.  You know how to do that check.

>  2) Are you sure you answered the question he asked? Jeff asked if
>     it is valid for the compiler to REQUIRE YOU TO include the
>     prototype. To me, "require you to" means "refuse to generate
>     code unless you...". That's a different issue. Unless a program
>     violates a syntax rule or a semantic constraint, the compiler
>     can at most issue a warning but must still generate code. I
>     believe (please correct me if I'm wrong) that a program can
>     fail to be strictly conforming (and even fail to be conforming)
>     without violating any semantic constraints. Is this correct?

The standard does not really define "REQUIRE YOU TO", although the word
"shall" and the word "undefined" are meta-defined in a meta-standard.
I would say that a compiler can require you to include the prototype.
-- 
Norman Diamond, Nihon DEC    diamond@tkov50.enet.dec.com
                                    (tkou02 is scheduled for demolition)
We steer like a sports car:  I use opinions; the company uses the rack.

lewine@dg-rtp.dg.com (Donald Lewine) (10/18/90)

In article <12826@crdgw1.crd.ge.com>, volpe@underdog.crd.ge.com
(Christopher R Volpe) writes:
|> 
|> Two questions:
|>   1) Can you point me to a reference in the standard that says that
|>      old-style declarations are insufficient for a variable argument
|>      function in a strictly conforming program? Or are old style
declarations
|>      insufficient for ANY kind of function in a strictly conforming
|>      program?

OK.  See section 3.7.1: "If a function that accepts a variable number
of arguments is defined without a parameter type list that ends with
the ellipsis notation, the behavior is undefined."

This allows the compiler to generate a different calling sequence
for functions with a fixed number of argument and a variable number
of arguments.  See section 4.8 in the rationale.

|> 
|>   2) Are you sure you answered the question he asked? Jeff asked if
|>      it is valid for the compiler to REQUIRE YOU TO include the
|>      prototype. To me, "require you to" means "refuse to generate
|>      code unless you...". That's a different issue. Unless a program
|>      violates a syntax rule or a semantic constraint, the compiler
|>      can at most issue a warning but must still generate code. I
|>      believe (please correct me if I'm wrong) that a program can
|>      fail to be strictly conforming (and even fail to be conforming)
|>      without violating any semantic constraints. Is this correct?
Well, if the implementation uses one calling sequence (say, with
arguments in registers) for functions with a known number of arguments
and uses a different calling sequence (say, with arguments on the
stack) for functions with a variable number of arguments, the 
generated code will not call the library correctly unless the function
is correctly declared.  I will admit that you may not get an error 
message, but the code will not work!
 
Note also that the definition of ANSI C was done to allow a compiler
to generate calls with arguments in registers and several new RISC
compilers take advantage of that.

--------------------------------------------------------------------
Donald A. Lewine                (508) 870-9008 Voice
Data General Corporation        (508) 366-0750 FAX
4400 Computer Drive. MS D112A
Westboro, MA 01580  U.S.A.

uucp: uunet!dg!lewine   Internet: lewine@cheshirecat.webo.dg.com

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/18/90)

In article <1964@ccadfa.adfa.oz.au> Christopher-Vance@adfa.oz.au writes:
>gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>| Yes, you definitely must have a prototype in scope before calling a
>| variable-argument function in a strictly conforming program.
>Which means that gcc -ansi on a Pyramid cannot compile such a thing. I am
>informed that the only way to make printf work is to *omit* the prototype.

As I said before, you should rely on <stdio.h> to properly declare printf().
If <stdio.h> is not included at all, then the C standard guarantees that you
could declare printf() directly in your program, providing that you use the
prototype specified in the standard.  "extern int printf();" on the other
hand has undefined behavior.

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/18/90)

In article <PDS.90Oct17103016@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>I see no reason you could just not prototype anything, however:
>    int printf();
>This should cause no problems.

No, that's wrong.  As point of contact when the <stdarg.h> macros were
being worked out, I received many examples of implementations where
such a declaration would result in the wrong code being generated for
linkage to a variable-argument function.  This is reflected in the
requirements for strict program conformance in the C standard; the
above declaration is not strictly conforming, and it does matter.

markhall@pyrps5.pyramid.com (Mark Hall) (10/19/90)

In article <18561@haddock.ima.isc.com> karl@ima.isc.com (Karl Heuer) writes:
>In article <1964@ccadfa.adfa.oz.au> Christopher-Vance@adfa.oz.au writes:
>>gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>>| Yes, you definitely must have a prototype in scope [for printf()]
>>
>>Which means that gcc -ansi on a Pyramid cannot compile such a thing. I am
>>informed that the only way to make printf work is to *omit* the prototype.

There are two issues to cover here.  First, Doug said (quoting loosely)
"you must have a prototype in scope [for the *program* to be strictly
conforming]".  He didn't say that an ANSI compiler had to flag the
non-conformance.  Second, let me point out that on some architectures,
the calling sequence changes if you are calling a stdarg function (put
args on the stack instead of in registers, say).  If you don't have an
ellipsis prototype visible at the call site, the compiler will not know
to emit the correct calling sequence, and hence the program will die
mysteriously or give obscure results at runtime.  Does the ANSI
compiler which compiled this program have to tell you ahead of time
that you forgot the prototype?  No.  The adjective "conforming" applies
to programs, not compilers.

So does "gcc -ansi" really reject a program which calls a stdarg function 
without a prototype?  Does it manufacture a link-time check?  Otherwise,
how can it tell "printf" is a stdarg function?

>
>Presumably this is caused by having to link with the native implementation of
>printf(), and hence will be fixed when the FSF releases the GNU library.
>

I'm not sure what the problem is with the the Pyramid printf function
which is incompatible with gcc when you have an ellipsis prototype for 
printf.  Does gcc put ellipsis arguments on the stack or something?  
If so, why?

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

rfg@NCD.COM (Ron Guilmette) (10/19/90)

In article <14164@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <4026@otis.oakhill.UUCP> jeff@oakhill.UUCP (Jeff Enderwick) writes:
>>Is it legal for a compilation system to require prototypes when stdarg
>>functions are used ? It valid for the compiler to require you to include
>>the prototype:
>>	int printf ( const char*, ... );
>>before making the call:
>>	 printf ( "hello %d worlds\n", 5 );
>
>Yes, you definitely must have a prototype in scope before calling a
>variable-argument function in a strictly conforming program.
>
>For printf(), you should #include <stdio.h> instead of declaring it
>yourself.  You might get better results that way in some implementations.

Along the same lines, I also have a related question.

Now please excuse my almost total ignorance regarding the x3j11 requirements
regarding the contents of include files, but I don't immediately see where
(in 4.9.1) it says (explicitly) what function are required to be declared
within <stdio.h>.  Are all of the function listed in 4.9.4 thru 4.9.10
required to have declarations within <stdio.h>?  If so, are they required
to have prototyped declarations?  Non-prototyped?  Either?

Part of the reason that I ask is that I was doing some work recently on
a machine for which the va_list type is a structure, and I encountered
an odd problem.

I was porting some code to this machine, and I got an error on a hunk of
code like:

	#include <stdio.h>
	...
	...
	va_list args;
	...
	vfprintf (file, fmt, args);	/* <= error here */

as it turned out, the creators of the <stdio.h> file in question had cheated
and put a declaration like the following in it:

	int vfprintf (FILE *, const char *, void *);

Obviously, that last formal parameter type is not correct!  That's why I
got an error at the call.

I tried changing the last formal type to (a more correct) `va_list', but
when I did that this changed the <stdio.h> file into something that could
*not* be included ALL BY ITSELF into *any* given file.  Rather, it now always
had to be preceeded by a #include <stdarg.h>.

So what it the `correct' thing to have in the <stdio.h> file regarding the
vfprintf function (and friends)?
-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

darcy@druid.uucp (D'Arcy J.M. Cain) (10/19/90)

In article <1964@ccadfa.adfa.oz.au> Christopher-Vance@adfa.oz.au writes:
>gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>| Yes, you definitely must have a prototype in scope before calling a
>| variable-argument function in a strictly conforming program.
>
>Which means that gcc -ansi on a Pyramid cannot compile such a thing. I am
>informed that the only way to make printf work is to *omit* the prototype.

Is gcc on the Pyramid broken that badly?  On my SysV 386 system:

$ cat ptest.c
extern int printf(const char *format, ...);
int main(void) { printf("%d %s\n", 5, "Hello world"); return(0); }
$ gcc -Wall -ansi ptest.c -o ptest
$ ptest
5 Hello world
$

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   I support gun control.
West Hill, Ontario, Canada         |   Let's start with the government!
+ 416 281 6094                     |

volpe@underdog.crd.ge.com (Christopher R Volpe) (10/19/90)

To everyone who responded:
  Thank you for the explanations and the Standard references.

==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

chris@mimsy.umd.edu (Chris Torek) (10/19/90)

In article <2150@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>Now please excuse my almost total ignorance regarding the x3j11
>requirements regarding the contents of include files, but ...

To aid in the confusion, note that ANSI C makes no requirements at
all of this sort (since it nowhere requires that there be any files
at all).  The requirements are not `contents of include files' but
rather `behaviour of the compiler upon seeing ``#include <stdio.h>'' '
(and other standard headers).

If we consider `conventional Unix implementations', however:

>I don't immediately see where (in 4.9.1) it says (explicitly) what
>function are required to be declared within <stdio.h>.  Are all of
>the function listed in 4.9.4 thru 4.9.10 required to have declarations
>within <stdio.h>?  If so, are they required to have prototyped
>declarations?

Yes, and yes (unless the compiler implements them as `built in functions'
that are somehow enabled by the `#include').

>... on a machine for which the va_list type is a structure ... I
>encountered an odd problem. ... as it turned out, the creators of
>the <stdio.h> file in question had cheated and put a declaration
>like the following in it:
>
>	int vfprintf (FILE *, const char *, void *);

(but the type of `va_list' is not `void *').

>Obviously, that last formal parameter type is not correct!  That's why I
>got an error at the call.

As it happens, `void *' is `good enough' to hold any pointer type.
This machine's <stdio.h> contains a questionable, but legal, prototype
for vfprintf (provided that it *works* of course).  If the compiler
generates warnings, it can still be considered ANSI conformant---the
standard says nothing about excessive warnings.  Nonetheless, I
personally would like to know about such compilers that I might avoid
them entirely.

>I tried changing the last formal type to (a more correct) `va_list', but
>when I did that this changed the <stdio.h> file into something that could
>*not* be included ALL BY ITSELF into *any* given file.  Rather, it now always
>had to be preceeded by a #include <stdarg.h>.
>
>So what it the `correct' thing to have in the <stdio.h> file regarding the
>vfprintf function (and friends)?

This is one of those sticky implementation issues the ANSI standard
leaves up to the implementor.

Doug Gwyn has in the past suggested something along these lines:

	/* stdarg.h extract */
	typedef int va_list[3];

	/* stdio.h extract */
	int vfprintf(FILE *, const char *, int *);

where <stdio.h> `knows' what the stdarg.h va_list type is.  This makes
<stdio.h> machine-dependent; I consider this to be bad practise.

The 4.3BSD-reno release <std*.h> headers use a different mechanism.
A single file, <machine/machtypes.h>, contains all the machine-dependent
type definitions, using the `hidden' (reserved to implementor) name
space, and usually using preprocessor macros.  For instance, the
<machine/machtypes.h> for a VAX reads (abbreviated):

	#ifndef	_MACHTYPES_H_
	#define	_MACHTYPES_H_
	#define	_PTRDIFF_T_	int			/* ptr1 - ptr2 */
	#define	_VA_LIST_	char *			/* va_list */
	#define	_WCHAR_T_	unsigned short		/* wchar_t */
	#define	_SIZE_T_	unsigned int		/* sizeof() */
	#define	_CLOCK_T_	unsigned long		/* clock() */
	#define	_TIME_T_	long			/* time() */
	#endif

and <stdio.h> then says, in part,

	#include <machine/machtypes.h>
	#ifdef	_SIZE_T_
	typedef	_SIZE_T_ size_t;
	#undef	_SIZE_T_
	#endif
     /* some declarations deleted */
	int vfprintf(FILE *, const char *, _VA_LIST_);

while <stdarg.h>, in part,

	#include <machine/machtypes.h>
	typedef _VA_LIST_ va_list;

On a machine requiring a pointer to a structure, <machine/machtypes.h>
might read in part:

	typedef struct __va_list { /* contents */ } _VA_LIST_;

and no changes to any of the machine-independent headers are necessary.

The funny business with _SIZE_T_ is there so that <string.h> can also
contain a typedef for size_t, yet including both <stdio.h> and <string.h>
still works.  SunOS 4.x releases have the typedefs done directly in
a separate header, but this is erroneous, as it means that the
following conforming program fragment fails to compile:

	#include <string.h>
	nlink_t(const char *s) { return (strlen(s) > 10); }
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/19/90)

In article <2150@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>Now please excuse my almost total ignorance regarding the x3j11 requirements
>regarding the contents of include files, but I don't immediately see where
>(in 4.9.1) it says (explicitly) what function are required to be declared
>within <stdio.h>.  Are all of the function listed in 4.9.4 thru 4.9.10
>required to have declarations within <stdio.h>?  If so, are they required
>to have prototyped declarations?  Non-prototyped?  Either?

Section 4.1.2.1 says: "Each header declares or defines all identifiers
listed in its associated section, ..."  While it does not explicitly
require that prototypes be used, a strictly conforming program must
assume that the standard headers might use prototypes.  Otherwise, it
would be depending on undefined behavior.

Of course it is expected that high-quality implementations WOULD use
prototypes in the standard headers, because that would produce better
diagnostic capabilities due to being able to check argument types.

>... put a declaration like the following in it:
>	int vfprintf (FILE *, const char *, void *);
>I tried changing the last formal type to (a more correct) `va_list', ...

<stdio.h> must not rely on the inclusion of <stdarg.h> nor include
<stdarg.h> itself.  The v*() declarations in <stdio.h> should have
the appropriate type directly used in the declaration (i.e. not via
a typedef), or else they should use an implementation-reserved
identifier for the typedef.  For example:
	/* <stdio.h> example implementation (partial) */
	#include <sys/cdefs>	/* defines __va_list etc. */
	/* [FILE defined here] */
	int vfprintf(FILE *, const char *, __va_list);
With this technique, the same file (<sys/cdefs>) can be used in the
implementation of both <stdio.h> and <stdarg.h>.

steve@taumet.com (Stephen Clamage) (10/20/90)

rfg@NCD.COM (Ron Guilmette) writes:

!Now please excuse my almost total ignorance regarding the x3j11 requirements
!regarding the contents of include files, but I don't immediately see where
!(in 4.9.1) it says (explicitly) what function are required to be declared
!within <stdio.h>.  Are all of the function listed in 4.9.4 thru 4.9.10
!required to have declarations within <stdio.h>?  If so, are they required
!to have prototyped declarations?  Non-prototyped?  Either?

Section 4.1.2.1 says that a header must declare or define all identifiers
in its associated section.  I find it hard to read the standard to say
that non-prototype declarations are OK, but that may be prejudice.  I
haven't found an explicit statement that full prototypes are required.

! ... the creators of the <stdio.h> file in question had cheated
!and put a declaration like the following in it:
!	int vfprintf (FILE *, const char *, void *);
!Obviously, that last formal parameter type is not correct!

Yes, they cheated, and this is not standard-conforming.  The prototype
must match the one in the standard.

!I tried changing the last formal type to (a more correct) `va_list', but
!when I did that this changed the <stdio.h> file into something that could
!*not* be included ALL BY ITSELF into *any* given file.  Rather, it now always
!had to be preceeded by a #include <stdarg.h>.

!So what it the `correct' thing to have in the <stdio.h> file regarding the
!vfprintf function (and friends)?

<stdio.h> cannot just #include <stdarg.h>, since no header may include
any of the others.  The implementor cannot require you to #include
<stdarg.h> prior to <stdio.h>.  The implementor must supply a prototype for
functions which are equivalent to using the typedefs in the non-included
header file.  The implementor supplies all the headers, so this is
possible, apart from being required.

So in <stdarg.h> we might have:
	struct _T { .... };
	typedef struct _T va_list[2];

Then in <stdio.h> we would have:
	struct _T;
	int vfprintf(FILE *, const char*, struct _T*);	

This meets all of the ANSI requirements.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/21/90)

In article <483@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>!	int vfprintf (FILE *, const char *, void *);
>!Obviously, that last formal parameter type is not correct!
>Yes, they cheated, and this is not standard-conforming.  The prototype
>must match the one in the standard.

Presumably the declaration was correct for the implementation being
used as a basis for modification by the original poster.  I.e., I bet
that void* was the type of va_list in that implementation.  The
spellings of the prototypes given in the standard need not be used in
a conforming implementation; however, the types of the specified
library functions, objects, etc. must be compatible with the ones in
the standard.

>Then in <stdio.h> we would have:
>	struct _T;
>	int vfprintf(FILE *, const char*, struct _T*);	
>This meets all of the ANSI requirements.

I don't think so.  You've given a parameter an incomplete type.

rfg@NCD.COM (Ron Guilmette) (10/22/90)

In article <27066@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
<In article <2150@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
<>... on a machine for which the va_list type is a structure ... I
<>encountered an odd problem. ...
...
<
<As it happens, `void *' is `good enough' to hold any pointer type.

So what?

<This machine's <stdio.h> contains a questionable, but legal, prototype
<for vfprintf (provided that it *works* of course).  If the compiler
<generates warnings, it can still be considered ANSI conformant...

The <stdio.h> contains what I feel is (or shoud be) an *illegal* prototype
for vprintf().

Note that I said that on this particular machine, va_list is a *struct*
type (*not* a pointer to struct type).  Therefore, declaring the last
parameter for vprintf() as a void* is certainly not going to work right.

I just wanted to clarify that.

-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

rfg@NCD.COM (Ron Guilmette) (10/22/90)

In article <14195@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>Section 4.1.2.1 says: "Each header declares or defines all identifiers
>listed in its associated section, ..."  While it does not explicitly
>require that prototypes be used, a strictly conforming program must
>assume that the standard headers might use prototypes.  Otherwise, it
>would be depending on undefined behavior.

Allow me to stray a bit from my original question (which has been adequately
answer by a number of posters -- thank you all).

If I understand you correctly Doug, you are saying that printf() could
be declared in <stdio.h> in an unprototyped form (in a standard conforming
implementation).

This gives me pause.

It seems  that GCC (which is occasionally known to be standard conforming :-)
will complain about:

	extern int foo ();
	extern int foo (int, ...);

It says:

	problem.c:2: conflicting types for `foo'
	problem.c:2: A parameter list with an ellipsis can't match
	problem.c:2: an empty parameter name list declaration.
	problem.c:1: previous declaration of `foo'

Therefore, I imagine that it would also complain about:

	extern int printf ();
	extern int printf (const char *, ...);

Now if the first declaration was in <stdio.h> and if the second was in my
(standard conforming?) program, I believe that GCC would also still complain
(correctly, I believe).

So if the declarations in `system' include files are allowed to be either
prototyped or unprototyped, does this imply that my standard conforming
programs must *not* contain (potentially conflicting) declarations for
things which the standard requires be declared in any of the `system'
include files which my program happens to include?

><stdio.h> must not rely on the inclusion of <stdarg.h> nor include
><stdarg.h> itself...

I understand the `non-reliance' rule (and it even makes sense), but what
about this second rule (i.e. that <stdio.h> cannot include <stdarg.h>)?
I believe that such a rule exists, but just out of curiosity, which section
of the standard is that rule given in?

Also, what could be the reason for such a rule?  Isn't it a bit
superfluous?  Could it not be trivially circumvented by placing all of the
stuff that would normally go into <stdarg.h> into some other file (e.g.
<foobar.h>) and then having both <stdio.h> and <stdarg.h> include <foobar.h>?

-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

chris@mimsy.umd.edu (Chris Torek) (10/22/90)

In article <2173@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>Note that I said that on this particular machine, va_list is a *struct*
>type (*not* a pointer to struct type).  Therefore, declaring the last
>parameter for vprintf() as a void* is certainly not going to work right.

True.  I made the assumption that the system on that machine actually
worked, and guessed (wrongly) that you dropped the `pointer to' somewhere
along the line (easy to do in a Usenet posting where there is no compiler
to catch such errors :-) ).

I still find it hard to believe that someone would not test something
as basic as vprintf (or at least vfprintf---in my implementation, all
the printf routines eventually call vfprintf).  This is sort of like
sending a car to the dealer and forgetting to put in an engine.  Surely
*someone* would notice before selling the thing?
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/23/90)

In article <2174@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>If I understand you correctly Doug, you are saying that printf() could
>be declared in <stdio.h> in an unprototyped form (in a standard conforming
>implementation).

In some implementations it might work, not necessarily in all.

>So if the declarations in `system' include files are allowed to be either
>prototyped or unprototyped, does this imply that my standard conforming
>programs must *not* contain (potentially conflicting) declarations for
>things which the standard requires be declared in any of the `system'
>include files which my program happens to include?

A strictly conforming program must not misdeclare any of the standard
library functions (consequence of 4.1.2.1).  Also (see 4.1.6), special
care must be taken if you both include the standard header and declare
one of its functions yourself.

>I understand the `non-reliance' rule (and it even makes sense), but what
>about this second rule (i.e. that <stdio.h> cannot include <stdarg.h>)?
>I believe that such a rule exists, but just out of curiosity, which section
>of the standard is that rule given in?

4.1.2, 4.1.2.1.  Note also that #include <...> syntax does not imply that
any of the standard headers actually exist as files that look like pieces
of C source code; thinking of the standard headers as included files is
misleading.

>Also, what could be the reason for such a rule?

So that the programmer knows precisely what the effect of including a
standard header will be.

>Isn't it a bit superfluous?  Could it not be trivially circumvented by
>placing all of the stuff that would normally go into <stdarg.h> into
>some other file (e.g. <foobar.h>) and then having both <stdio.h> and
><stdarg.h> include <foobar.h>?

No, that wouldn't get around the problem of having #include <stdio.h>
defining one or more va_* identifiers as a side effect, which is not
allowed.

A way to do this right has been described previously in this newsgroup.

henry@zoo.toronto.edu (Henry Spencer) (10/23/90)

In article <27098@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>I still find it hard to believe that someone would not test something
>as basic as vprintf (or at least vfprintf---in my implementation, all
>the printf routines eventually call vfprintf).  This is sort of like
>sending a car to the dealer and forgetting to put in an engine.  Surely
>*someone* would notice before selling the thing?

Considering the number of things in (to pick purely random examples :-))
SVR4 and SunOS 4.1 that clearly were never tested, I fear Chris is being
naive.  Would that it were not so.
-- 
The type syntax for C is essentially   | Henry Spencer at U of Toronto Zoology
unparsable.             --Rob Pike     |  henry@zoo.toronto.edu   utzoo!henry

poser@csli.Stanford.EDU (Bill Poser) (10/23/90)

In article <27098@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>I still find it hard to believe that someone would not test something
>as basic as vprintf (or at least vfprintf---in my implementation, all
>the printf routines eventually call vfprintf).  This is sort of like
>sending a car to the dealer and forgetting to put in an engine.  Surely
>*someone* would notice before selling the thing?

One untested library function is nothing at all. I've seen a whole
compiler that didn't work. Version 5.22 of HP-UX (probably others,
but that's the one I know about for sure) had an F77 compiler that
generated grossly incorrect assembler. The assembler gagged on
EVERYTHING I tried. Obviously nobody had run the F77 compiler.

						Bill Poser

rfg@NCD.COM (Ron Guilmette) (10/28/90)

In article <27098@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
<In article <2173@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
<>Note that I said that on this particular machine, va_list is a *struct*
<>type (*not* a pointer to struct type).  Therefore, declaring the last
<>parameter for vprintf() as a void* is certainly not going to work right.
<
<True.  I made the assumption that the system on that machine actually
<worked...

Just to clarify, the <stdio.h> file that contained the travesty that I
described earlier was a part of somebody's broken version of an uncompleted
U*IX-like system.

It had not yet been fully tested and was not yet fully operational (as
should be evident, based upon the brokenness of the <stdio.h> file).

I apologize to all concerned if I gave you the impression that the bogus
declaration for vprintf() that I described came out of a working system.
It didn't.

-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.