Re: Question about multiple files
From: Marty (marty_at_sorry.com)
Date: 07/15/04
- Next message: Marty: "Re: Question about multiple files"
- Previous message: Barry Schwarz: "Re: C and string pointers"
- In reply to: Karl Heinz Buchegger: "Re: Question about multiple files"
- Next in thread: Marty: "Re: Question about multiple files"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Thu, 15 Jul 2004 11:22:19 +0930
"Karl Heinz Buchegger" <kbuchegg@gascad.at> wrote in message
news:40F4ED84.14DAA345@gascad.at...
> Marty wrote:
> >
> > Hi guys,
> >
> > Just a quick one about writing code spanning multiple files.
> >
> > Say I have a few files defining classes or global functions. When I want
to
> > use one in the other, I include its header file to get the declarations
> > available. This I can understand, but say I declare with extern. Does
this
> > mean I dont have to include a header file of where the function is
declared?
>
> No. extern just means: The actual definition is somewhere else. This is
what
> the whole thing looks like, but it is defined somewhere else.
> You need extern for global variables. On function declarations you can
> use extern too, but usually it is not done. This is because for functions
> the compiler can differentiate between declaration and definition just
> by the syntax
>
> void foo(); // this is a declaration
>
> void foo()
> {
> } // this is a definition
>
> but with global variables thats no longer the case
>
> int i; // this is a definition, but what would
> // a declaration look like ? ...
>
> extern int i; // ... like this: just precede it with 'extern', discard
> // all initializations and it becomes a declaration.
>
> So why is that important?
> Because there is the so called 'One Definition Rule' (ODR). It says:
> for the very same item in a whole program, you can have as many
declarations
> as you want (as long as all of them match), but you can have only one
definition.
>
> >
> > When I link all the object files together, will the function resolve to
any
> > declaration it finds and in this way can I write code expecting it to be
> > there in the future. Say by blocking with a #ifdef maybe.
>
> I'm not sure I understand what you are trying to ask in this paragraph.
>
> So just guessing your question right now:
> It works like this. Say you write a program which consists of 2 files
> containing functions:
>
>
> main.c foo.c
> +----------------------------+ +------------------------+
> | | | #include <stdio.h> |
> | int main() | | |
> | { | | void foo() |
> | foo(); | | { |
> | } | | printf( "Hello\n" ); |
> | | | } |
> +----------------------------+ +------------------------+
>
> You try to compile both of those files in order to get object code files
> for each of them, which in turn will be linked together (plus adding the
> runtime library) to form the complete program. The important thing is:
> when you compile main.c the compiler knows nothing about foo.c and
> vice versa. Each file is compiled independently of all others.
>
> But there is a problem when compiling main.c
> When the compiler reaches the line foo(); it will emit an error. Why?
Because
> it never heard about something called foo. It could be a typing error or a
> non existent function or a variable misused or ... In any case there is
> something wrong and the compiler will barf.
> So what to do about it?
> Well. Simple, just tell the compiler that there is indeed somewhere a
thing
> called foo. That it is a function and what its return type and the data
types
> of the arguments are. You could do this eg this way:
>
> main.c foo.c
> +----------------------------+ +------------------------+
> | void foo( void ); | | #include <stdio.h> |
> | int main() | | |
> | { | | void foo() |
> | foo(); | | { |
> | } | | printf( "Hello\n" ); |
> | | | } |
> +----------------------------+ +------------------------+
>
> Now main.c is compilable and you can create a program.
> Say you continue working on this program and introduce a second function
> foo2():
>
> main.c foo.c
> +----------------------------+ +------------------------+
> | void foo( void ); | | #include <stdio.h> |
> | foid foo2( void ); | | |
> | int main() | | void foo() |
> | { | | { |
> | foo(); | | printf( "Hello\n" ); |
> | foo2(); | | } |
> | } | +------------------------+
> +----------------------------+
>
> foo2.c
> +------------------------+
> | void foo(); |
> | |
> | void foo2() |
> | { |
> | foo(); |
> | } |
> +------------------------+
>
> Compile all 3 files, link them and run the executable. All is well.
> *BUT*
> During your development you reach a point where you have to change the
function
> foo(). It now has to take an argument, lets say an int. So you start
changing
> things. But since the program got to big you make a mistake and miss one
> occourence of foo. The whole thing looks like this:
>
> main.c foo.c
> +----------------------------+ +------------------------+
> | void foo( int ); | | #include <stdio.h> |
> | foid foo2( void ); | | |
> | int main() | | void foo( int a ) |
> | { | | { |
> | foo( 2 ); | | printf( "Hello\n" ); |
> | foo2(); | | printf( "%d\n", a ); |
> | } | | } |
> +----------------------------+ +------------------------+
>
> foo2.c
> +------------------------+
> | void foo(); |
> | |
> | void foo2() |
> | { |
> | foo(); |
> | } |
> +------------------------+
>
> See the problem?
> I changed the declaration of foo in main.c. But i missed the one in foo2.c
> Important: When the compiler compiles foo2.c it knows nothing about foo.c
> or about the correct declaration of foo(). The compiler trusts you!
> So the compiler will misses that glitch too! It will happily compile
foo2.c,
> the linker misses it too (since this is C and not C++) and builds an
executable
> which, well, anything may happen: the program crashes, it outputs a weird
number,
> it reboots your system, ....
>
> So there must be a better way then including the declaration in each
translation
> unit. And this solution is: a header file.
>
>
> main.c foo.c
> +----------------------------+ +------------------------+
> | #include "foo.h" | | #include <stdio.h> |
> | foid foo2( void ); | | |
> | int main() | | void foo( int a ) |
> | { | | { |
> | foo( 2 ); | | printf( "Hello\n" ); |
> | foo2(); | | printf( "%d\n", a ); |
> | } | | } |
> +----------------------------+ +------------------------+
>
> foo2.c
> +------------------------+
> | #include "foo.h" |
> | |
> | void foo2() |
> | { |
> | foo(); |
> | } |
> +------------------------+
>
> foo.h
> +------------------+
> | void foo( int ); |
> | |
> +------------------+
>
> So why is that better?
> Because now the declaration is physically at exactly one place! When you
> need to do some changes in the interface of function foo(), you have to
edit
> exactly 2 files: the implementation in foo.c and the declaration in foo.h
> All other files, since they include foo.h, will get this updated
declaration
> automatically. That eg. means that the compiler now will detect the error
> in foo2.c and will tell me that the call to function foo() is in error,
since
> foo() expects an int, which is not provided.
>
> But also note. In the whole program, that is files main.c, foo.c,
> foo2.c there are multiple declarations of function foo(). When main.c is
compiled
> it sees a declaration of foo(), when foo2.c is compiled it sees a
declaration
> of function foo(). No problem with that, all of them match. They have to
match,
> since all the declarations come from including file foo.h. But there is
only
> one definition (implementation): the one in foo.c. So from the language
point
> of view, all is well.
>
>
> --
> Karl Heinz Buchegger
> kbuchegg@gascad.at
Thankyou, thats what I wanted to know.
- Next message: Marty: "Re: Question about multiple files"
- Previous message: Barry Schwarz: "Re: C and string pointers"
- In reply to: Karl Heinz Buchegger: "Re: Question about multiple files"
- Next in thread: Marty: "Re: Question about multiple files"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|