[comp.std.c] struct* mention before declaration/definition

msw@unix.cis.pitt.edu (Matt S Wartell) (06/21/91)

I was porting some code to a PC under Turbo C++ 1.0 and encountered
some wierdness.  Turbo C claims to be ANSI conformant, so I wanted
to know if this is proper behavior.

The code I am porting has its header files out of order, so one of the
source files pre-processes into:

	/* declaration of function */
	void add_version(int a, struct B *b);

	/* definition of structure */
	struct B {
		...
	};

	/* definition of function */
	void add_version(int a, struct B *b)
	{
		...
	}

When the compiler gets to the function definition, it complains of a type
mismatch in parameter b.  It is our impression that the compiler should
produce an error at the function _declaration_ because the declaration
uses an undefined, undeclared type.

Does anyone know why the compiler did this, and whether or not it should
have?

Thanks in advance.
-- 
matt wartell, university of pittsburgh             msw@unix.cis.pitt.edu

volpe@camelback.crd.ge.com (Christopher R Volpe) (06/22/91)

In article <142762@unix.cis.pitt.edu>, msw@unix.cis.pitt.edu (Matt S
Wartell) writes:
|>	/* declaration of function */
|>	void add_version(int a, struct B *b);
                                ^^^^^^^^ Implicit declaration of incomplete
                                         type whose scope is the
prototype itself.
                                         You don't want this.

|>
|>	/* definition of structure */
|>	struct B {
|>		...
|>	};
        Declaration of new type not yet seen at this scope. This is fine.
 
|>
|>	/* definition of function */
|>	void add_version(int a, struct B *b)
                                ^^^^^^^^
                                Reference to type already declared in outer
                                scope above. This type is a DIFFERENT TYPE
                                from the one that appears in the prototype
                                declaration.
|>	{
|>		...
|>	}
|>
|>When the compiler gets to the function definition, it complains of a type
|>mismatch in parameter b.  It is our impression that the compiler should
|>produce an error at the function _declaration_ because the declaration
|>uses an undefined, undeclared type.
|>-- 
|>matt wartell, university of pittsburgh             msw@unix.cis.pitt.edu

The compiler is correct. Move the declaration of struct B before the
prototype.

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

mccrady@torolab6.vnet.ibm.com ("Don McCrady") (06/22/91)

> From: msw@unix.cis.pitt.edu (Matt S Wartell)
>
>       /* declaration of function */
>       void add_version(int a, struct B *b);    /* 1 */
>
>       /* definition of structure */
>       struct B {                               /* 2 */
>               ...
>       };
>
>       /* definition of function */
>       void add_version(int a, struct B *b)     /* 3 */
>       {
>               ...
>       }
>
> When the compiler gets to the function definition, it complains of a
> type mismatch in parameter b.  It is our impression that the compiler
> should produce an error at the function _declaration_ ...

A struct tag can be introduced before the structure has been defined,
and is called an incomplete type.  Thus, the declaration of function
add_version() is entirely legal (but not too useful, as I'm about
to explain).

I've marked up your example with /* n */ to refer to specific lines.

You should be getting an error message on or about the function
definition (/* 3 */) because of C's scoping rules for function
declarations.

On the function declaration (/* 1 */), the left parenthesis that begins
the parameter list opens a new scope.  The following identifiers are
local to that scope: a, B, and b.  When the right parenthesis that ends
the parameter list is seen, this scope closes, and all these identifiers
disappear, including B.  Note that B was an incomplete type that can
never be completed, since nobody from an outside scope can peek inside
this one.

On /* 2 */, a new identifier B is introduced.  Since we're at a
different scope, this is an entirely different B than the one we
introduced at /* 1 */.  Just to show the distinction, I'll call
this new identifier B' (B-prime).

On /* 3 */, the compiler should notice that the definition of function
add_version() does not match the original prototype.  Why?  Because
the second parameter is different:  the function declaration declared
its second parameter to be a struct B *, and the function definition
declared its second parameter to be a struct B' *.  Not compatible,
hence the error message.

The real problem, as you mentioned, is that the declarations are
out of order.  If you had put the declaration for struct B before
everything else, all occurrences of struct B would have resolved
to the same identifier.

     ++don;