[comp.std.c] gcc 1.35 conflicting types message?

ado@elsie.UUCP (Arthur David Olson) (05/05/89)

The GNU C Compiler, version 1.35, now generates a "conflicting types" message
and refuses to compile when confronted with code such as. . .

	Script started on Thu May  4 22:03:53 1989
	elsie$ cat try.c
	extern int	whatever();
	extern int	whatever(char * format, ...);
	elsie$ /usr/local/bin/gcc -v try.c
	gcc version 1.35
	 /usr/local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -D__HAVE_68881__ -Dmc68020 try.c /tmp/cca15784.cpp
	GNU CPP version 1.35
	 /usr/local/lib/gcc-cc1 /tmp/cca15784.cpp -quiet -dumpbase try.c -version -o /tmp/cca15784.s
	GNU C version 1.35 (68k, MIT syntax) compiled by GNU C version 1.35.
	try.c:2: conflicting types for `whatever'
	try.c:2: A parameter list with an ellipsis can't match
	try.c:2: an empty parameter name list declaration.
	try.c:1: previous declaration of `whatever'
	elsie$ exit

	script done on Thu May  4 22:04:12 1989

If you can tell me wheter "try.c" above is [d[p]]ANS-compliant or not,
I'd appreciate hearing from you by electronic mail.  I'd also appreciate
opinions on whether the code should be accepted even if it isn't compliant,
so that newly written header files can contain prototypes without introducing
the possibility of clashes with old-style header files.
-- 
			Space:  Canada, 0 tries ever.
	Arthur David Olson    ado@ncifcrf.gov    ADO is a trademark of Ampex.

pardo@june.cs.washington.edu (David Keppel) (05/06/89)

An answer and a question:

ado@elsie.UUCP (Arthur David Olson) writes: (paraphrased)
>gcc v. 1.35 generates a "conflicting types" message
>and refuses to compile when confronted with code such as. . .
>
>	extern int	whatever();
>	extern int	whatever(char * format, ...);

You can generate old and new-style functions declarations by doing
something like

    #ifdef __STDC__
	#define PROTO(x)	x
    #else
	#define PROTO(x)	()
    #endif

    extern int	whatever PROTO((char *format, ...));

Now the question:  I have asserted several times that you cannot
(portably) call between prototyped and non-prototyped code.  Thus, if
a library is compiled without prototypes, you can call it where a
prototyped declaration is in scope.  Similarly, if the thing (library)
was compiled with prototypes, it cannot be called from code that does
not have prototypes in scope.

Thus, the above macros (based on using __STDC__) are broke if you ever
use them to call across compiler types.

Yes?  No?  Maybe so?

	;-D on  ( Your local dime store philosipher )  Pardo
-- 
		    pardo@cs.washington.edu
    {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo

rang@cpsin3.cps.msu.edu (Anton Rang) (05/06/89)

In article <8124@june.cs.washington.edu> pardo@june.cs.washington.edu (David Keppel) writes:

>An answer and a question:

>ado@elsie.UUCP (Arthur David Olson) writes: (paraphrased)
>>gcc v. 1.35 generates a "conflicting types" message
>>and refuses to compile when confronted with code such as. . .
>>
>>	extern int	whatever();
>>	extern int	whatever(char * format, ...);

>You can generate old and new-style functions declarations by doing
>something like

>    #ifdef __STDC__
>	 #define PROTO(x)	x
>    #else
>	 #define PROTO(x)	()
>    #endif

>    extern int	whatever PROTO((char *format, ...));

  This works fine when you are writing your own functions.  I think
the problem that Mr. Olson was referring to was when you are trying to
add prototypes to standard libraries.  At least, that's the problem
I'm facing here--if you do "#include <stdio.h>" and then "#include
<proto/stdio.h>", our system (Sun-3/280) will prototype the calls
there.  I haven't gotten 1.35 up yet, but if the above error message
occurs in this situation, it means we have to either (1) give up
support for the standard C compiler, or (2) duplicate all the include
files, then edit them to use prototypes instead of externs.

>Now the question:  I have asserted several times that you cannot
>(portably) call between prototyped and non-prototyped code.

  In which cases would this be true?  The only time I can see it is if
you have a prototype which overrides a default type conversion; i.e.
if you have a function

	char *func(x)
	  char x;

then the obvious prototype "char *func(char x)" would be wrong.  Doing
the promotion gives you the prototype "char *func(int x)".  Is there
anything wrong with this that I'm missing?

+---------------------------+------------------------+-------------------+
| Anton Rang (grad student) | "VMS Forever!"         | VOTE on	         |
| Michigan State University | rang@cpswh.cps.msu.edu | rec.music.newage! |
+---------------------------+------------------------+-------------------+
| Send votes for/against rec.music.newage to "rang@cpswh.cps.msu.edu".   |
+---------------------------+------------------------+-------------------+

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/08/89)

In article <8124@june.cs.washington.edu> pardo@uw-june.UUCP (David Keppel) writes:
>Now the question:  I have asserted several times that you cannot
>(portably) call between prototyped and non-prototyped code.

Wrong.  <stdarg.h> does require a properly prototype for each variadic
function, but otherwise if the argument types agree after default
promotion rules are applied, a function can be declared either way.

ka@june.cs.washington.edu (Kenneth Almquist) (05/08/89)

>ado@elsie.UUCP (Arthur David Olson) writes: (paraphrased)
>>gcc v. 1.35 generates a "conflicting types" message
>>and refuses to compile when confronted with code such as. . .
>>
>>	extern int	whatever();
>>	extern int	whatever(char * format, ...);

That's because these are incompatible.  Bear with me for a few paragraphs
of explanation.

In traditional C, the number of arguments was not known at compile time.
If a subroutine declared three arguments you could pass it four arguments.
More usefully, you could pass the routine only two arguments if you
knew that it was going to only reference its first two arguments on a
particular call.

This feature of C made some people unhappy because the "natural" calling
sequence on some architectures requires a procedure to know how many
arguments it was called with.  An example is the 8086, where the "return
from subroutine" instruction pops the arguments to the subroutine off
the stack.  C compilers for the 8086 and similar architectures have had
to use a nonstandard calling sequences that do not require the callee
to know the number of arguments.  Two problems with using nonstandard
calling sequences are:

    1)	It is likely to make function calls slower, and
    2)  It makes interfacing to code written in other languages more
	difficult.

These problems (and possibly others) persuaded ANSI to require that
the actual number of arguments be the same as the number of arguments
declared, with the exception of functions which are explicitly declared
to be varadic.  (Apparently even thousands of PC users couldn't convince
ANSI to eliminate printf. :-))  In other words, compilers are still
required to support a form of subroutine call linkage which can handle
a varying number of arguments, but they are only required to use this
for procedures which are explicitly declared varadic.  For other
procedures, they are allowed to use calling conventions which require
the called procedure to know the number of arguments at compile time.

If a compiler takes advantage of this, then the compiler *must* know
whether a function is varadic or not when it generates a call to that
function.  For example, consider following program:

	main() {
		printf("Hello, world\n");
		exit(0);
	}

This program is legal in traditional C, but in ANSI C all sorts of nasty
things can happen.  For example, on some machines it might make sense to
have the callee *always* pop the arguments off the stack, and have the
caller pass in the number of arguments when the function is varadic.  In
this case, the printf routine will treat the "hello, world\n" string as
the number of arguments, and treat the next argument (which doesn't exist)
as the format string.  This will cause it to print out a bunch of garbage,
pop some huge number of arguments off the stack (since the address of the
"hello, world" string is likely to be a fairly large number), and return.
When the program tries to call "exit" the stack pointer may very well be
pointing at nonexistent memory, causing a core dump.  I expect that an
implementation which behaved like this would not sell very well, but it
would conform to ANSI C.

So to return to the original question, if you write

>>	extern int	printf();

this tells the C compiler that printf is not a varadic function.  The
subsequent declaration

>>	extern int	printf(char * format, ...);

tells the C compiler that printf *is* a varadic function.  Since the
compiler may need to know whether or not printf is varadic in order to
generate a call to it, giving the compiler conflicting information is
rightly made illegal.
				Kenneth Almquist

ado@elsie.UUCP (Arthur David Olson) (05/12/89)

Thanks to everyone who replied to my question about gcc 1.35 flagging
	extern int	whatever();
and
	extern int	whatever(char * format, ...);
as having conflicting types.  The consensus is that while the presence of a
"traditional"
	extern int	whatever();
declaration tells a conforming compiler/interpreter nothing about the
parameters of the function "whatever", it *does* represent a guarantee to
the compiler/interpreter that "whatever" takes some fixed number of arguments.

Folks interested in using gcc to compile X Window System applications may wish
to make the attached change to their "fixincludes" script.
-- 
		      Space:  Canada, 0 tries ever.
	Arthur David Olson    ado@ncifcrf.gov    ADO is a trademark of Ampex.

*** 1.5/fixincludes	Thu May 11 17:02:28 1989
--- 1.6/fixincludes	Thu May 11 17:02:28 1989
***************
*** 78,83 ****
--- 78,106 ----
  EOF
  fi
  
+ # Deal with yet another challenge, this in X11/Xmu.h
+ file=X11/Xmu.h
+ if [ -r $file ]; then
+   if [ ! -r ${LIB}/$file ]; then
+     mkdir ${LIB}/X11 2>&-
+     cp $file ${LIB}/$file >/dev/null 2>&1	\
+     || echo "Can't copy $file"
+     chmod +w ${LIB}/$file
+   fi
+ fi
+ 
+ if [ -r ${LIB}/$file ]; then
+   echo Fixing $file sprintf declaration
+   ex ${LIB}/$file <<EOF
+   /^extern char \*	sprintf();$/c
+ #ifndef __STDC__
+ extern char *	sprintf();
+ #endif /* !defined __STDC__ */
+ .
+   wq
+ EOF
+ fi
+ 
  echo 'Removing unneeded directories:'
  cd $LIB
  files=`find . -type d -print | sort -r`