gcc 1.35 conflicting types message?

Kenneth Almquist ka at june.cs.washington.edu
Mon May 8 17:04:39 AEST 1989


>ado at 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



More information about the Comp.std.c mailing list