C File Organisation

Programming, for all ages and all languages.
Post Reply
srg

C File Organisation

Post by srg »

Hi

One thing that I'm always confusing myself about with C is organising the variouse modules.

I've noticed in large projects, such as the linux kernel, there are often header files that are included into multiple c files. When I ever try to do this I end up with errors saying that a variable has been redeclared (or at least allready declared).

I'm, finding this very confusing.
Please could someone shed some light on this

Thanks
srg
Tim

Re:C File Organisation

Post by Tim »

You're defining a variable more than once :).

Consider these points:
1. You can only define a function or variable once within a program.
2. You can declare a function or variable as many times as you want. It must be declared at least once in each translation unit.
3. A translation unit is the contents of a C source file with each #include line replaced with the contents of the relevant include file.

Definitions look like this:

Code: Select all

int a_variable;
void a_function(int z)
{
    some_stuff();
}
Declarations look like this:

Code: Select all

extern int a_variable;
void a_function(int z);
extern void another_function(); // note: identical to previous line
Given this information, can you figure out a solution to your problem?

Note: An exception to rule (1) above is on functions and variables marked static. These are not visible from outside the translation unit where they are defined, so they can be defined many times (possibly in different ways) within a program, without interefering.
Tim

Re:C File Organisation

Post by Tim »

Also: You can only have one copy of a typedef, struct or union (in C++, also class) declaration within a translation unit. So a common idiom is to surround the contents of each header file in a #ifdef block to prevent the statements within being compiled more than once:

Code: Select all

// ---- header.h
#ifndef HEADER_H
#define HEADER_H

typedef struct lots_of declarations_here;

#endif // HEADER_H
srg

Re:C File Organisation

Post by srg »

That all makes a lot more sense, thanks!

If you think this in confusing, I've just started a very short Ada course and you basically have to multiple package "includes" just to write text to the screen and get a number from the keyboad :)

srg
Schol-R-LEA

Re:C File Organisation

Post by Schol-R-LEA »

Note to self: write a whole chapter on the preprocessor for the C and C++ tutorials. An early chapter.

Yes, but the 'with' and 'use' statements in Ada actually work rather differently than C '#include' directives. Not only does it work in a diferent manner, to actual behavior is different.

The first thing you have to understand is the the '#include' statement in C is actually a preprocessor directive, not a part of the language as it is compiled. The C preprocessor reads the entire source code before the compiler does, and makes textual changes to the code based on the directives and macros used. The 'textual' part is important; with the exception of #pragma directives, all of the effects of the preprocessor directives are on the source code itself. The #include directive, specifically, has the effect of 'replace this statement with the contents of the a named file'. It can, technically speaking, be any valid C source file; the usage of header files and separate declarations is a convention, albeit one borne out of long practice and many hard lessons.

The Ada 'with' and 'use' statements work differently. When an Ada program is compiled, a secondary file (or a special part of the object file, depending on the compiler) is generated, which contains all of the information about the publically accessible function and type declarations in the package (it is partly to make this process easier that Ada requires separate declaration and definition file sections). Unlike the C headers, this is not itself an Ada source file, but a data table of some sort, often in a binary format.

When a package makes a 'with' or statement, the compiler itself - not a preprocessor - checks the declaration data for the package in question, reading it from the compiled import file. While this is in some ways analogous to the #include directive, it works in a very different way. It also has the effect of a 'use namespace' directive in C++, in that it controls the visibility of a package's contents.

Ada's 'uses' directive has no exact equivalent in C, being (IIRC) a linker directive; it indicates that the functions in question should be linked to the file.

As for why you need several statements for even simple tasks, that's for two reasons. First, you need both a 'with' statement and a 'uses' statement for any package you intend to import (though if you are only using a few individual function calls from a package, it may be better to use the [tt]package.function[/tt] scoping syntax instead and not bother importing the whole package). I seem to recall that it is possible to use a 'with' statement alone, if you are importing a data structure or set of constants without any associated functions, but if so, it is rarely done. Second, the Ada libraries are designed to be much finer-grained than those in C; you need to use more import statements to get all the functions you need. Lastly, technically speaking, all of the basic data types ('character', 'integer', etc.) are defined in their own packages, not as part of the language per se; thus, just to use the basic data types requires one or more imports.

I could also add that the Java 'import' directive, the 'import/export' directives in Modula 2 and it's successors, and similar constructs in Eiffel, Sather, et. al., are generally closer to the Ada constructs than the C ones, though each has it's own quirks.

I advise you to take these assertions with a grain of salt, since they are based on recollections from the late 1980s, which may be incorrect. Also, I know that Ada has undergone a major revision (Ada 95) since I last studied it seriously. You may want to check the Ada references at http://www.adapower.com/ to get the accurate explanations. C&CW.
pr

Re:C File Organisation

Post by pr »

Tim Robinson wrote: You're defining a variable more than once :).

Consider these points:
1. You can only define a function or variable once within a program.
2. You can declare a function or variable as many times as you want. It must be declared at least once in each translation unit.
3. A translation unit is the contents of a C source file with each #include line replaced with the contents of the relevant include file.

Definitions look like this:

Code: Select all

int a_variable;
void a_function(int z)
{
    some_stuff();
}
Declarations look like this:

Code: Select all

extern int a_variable;
void a_function(int z);
extern void another_function(); // note: identical to previous line
Given this information, can you figure out a solution to your problem?

Note: An exception to rule (1) above is on functions and variables marked static. These are not visible from outside the translation unit where they are defined, so they can be defined many times (possibly in different ways) within a program, without interefering.
Post Reply