Modularisation

  • Thread starter Steffen Loringer
  • Start date
S

Steffen Loringer

Hi,

can anyone recommend a good wbeppage concerning modularisation of C
programs into different files?

Thanks to all of you
Steffen
 
A

Alexei A. Frounze

Steffen Loringer said:
can anyone recommend a good wbeppage concerning modularisation of C
programs into different files?

But what is the problem? Normally this is done by separating more or less
independent portions of the code into separate files. Just that. Of course
that may involve quite some coding, not just copy'n'pasting...
But as far as C goes, what's the problem?

Alex
 
S

Steffen Loringer

There is no real problem. But there may be rules for good coding etc...
I separated my functions "by function part of the program" into header
*.h and source *.c files.
I have to include many libraries for each *.h and *.c, does this make my
executable bigger at the end??

Thanks for your reply, Alexei!
 
A

Alexei A. Frounze

*.h should contain public info that's intended for use by the caller, e.g.:
- macros
- type definitions
- inline functinos (you may need to declare them as "static inline" --
depends on the compiler I guess)
- externs
*.c should contain everything else that's internal and not to be exposed to
the outer world.
This is as far as the .h vs .c goes.
But then you also should separate the code semantically, put in different .?
files the code for different things, e.g.:
- input/output management (better to make an abstract API for portability)
- system layer (synchronization primitives, interprocess communication and
everything else that's system-specific -- better to make an abstract API for
portability)
- general purpose data structure management (e.g. searching, sorting, lists,
trees, hashtables, etc)
- task-oriented data processing (can be anything, ranging from text
processing and conversion to signal processing (audio, video, whatever),
data compression/encryption, various computation tasks -- every distinct set
of operations deserves its own file (or set of a few files))
- auxiliary/miscellaneous/helper functions of small importance and maybe
frequent use

I'm not sure what libraries you're talking about, but separating the code
into several compilaion units must not make it any bigger. Actually, it can
make it smaller (if you put the code that may not be used at all into a
separate .c file -- its object code won't be linked in unless necessary).
Each library and object file is linked only once unless your tools are
broken or allow some degree of misuse.

Mind you, separation of the code into distinct units, better as much
independednt as possible, allows for simpler maintainance, testing and
debugging. That's the primary reason to do such a thing. And don't forget
that recompilation of a single huge .c file will take longer than
recompilation of a small one.

Alex
P.S. please don't top post.
A: Yep, Alice in the Wonderland had first to serve the cake out to a few
persons and only then cut it in parts.
Q: Really? I don't get it. Could you give me an example?
A: Because it makes the flow of events complicated
Q: Why top posting is bad?
 
M

Mark F. Haigh

Alexei A. Frounze wrote:
*.c should contain everything else that's internal and not to be exposed to
the outer world.

Oh really? Then where are funcations with external linkage defined?

I'm not sure what libraries you're talking about, but separating the code
into several compilaion units must not make it any bigger. Actually, it can
make it smaller (if you put the code that may not be used at all into a
separate .c file -- its object code won't be linked in unless necessary).

Misleading at best. This will generally *not* occur unless the linker
is told to, or the group of object files are made into a static archive
before linking.

Also, for a discussion about executable sizes to be meaningful, you
have to consider the effect of shared libraries if the system in
question uses them.
Each library and object file is linked only once unless your tools are
broken or allow some degree of misuse.

Again, misleading. Depends on the circumstance, and how your linker
handles mutually referential libraries.
Mind you, separation of the code into distinct units, better as much
independednt as possible, allows for simpler maintainance, testing and
debugging. That's the primary reason to do such a thing.
Agreed.

And don't forget
that recompilation of a single huge .c file will take longer than
recompilation of a small one.

Not by too much, on today's systems.


Mark F. Haigh
(e-mail address removed)
 
A

August Karlstrom

Alexei said:
But what is the problem? Normally this is done by separating more or less
independent portions of the code into separate files. Just that. Of course
that may involve quite some coding, not just copy'n'pasting...
But as far as C goes, what's the problem?

Since modularization is one of the weakest points of C you need some
good rules for how to do it. Still, even with an appropriate
modularization technique there is no way to declare types or (true)
constants with file scope (compare with Modula and Oberon).


August
 
E

Eric Sosman

August said:
Since modularization is one of the weakest points of C you need some
good rules for how to do it. Still, even with an appropriate
modularization technique there is no way to declare types or (true)
constants with file scope (compare with Modula and Oberon).

It's easy to declare types with file scope in C: Just Do It.

/*** foo.c ***/
struct s { int this; double that; }
struct s instance = { 42, 3.14 };
int getThis(struct s *sptr) {
return s->this;
}
/* More code using the `struct s' type freely */

/*** bar.c ***/
struct s anotherinstance = { -1, 98.6 };
/* sorry; won't compile: this code is outside the
scope of the `struct s' type declaration */

Constants are, I admit, harder to do. There's #define, but
prior to C99 it couldn't really declare a "constant" of compound
type other than string. There are enum identifiers, but they're
limited to integer constants. However, I don't see what these
peculiarities have to do with modularization.
 
P

pete

Alexei said:
*.h should contain public info that's intended for use by the caller, e.g.:
- macros
- type definitions
- inline functinos (you may need to declare them as "static inline" --
depends on the compiler I guess)

Why put inline functions in the .h file?
 
P

pete

Mark said:
Alexei A. Frounze wrote:


Oh really? Then where are funcations with external linkage defined?

All function definitions and object definitions
belong in the .c files, regardless of linkage,
as far as I know.
 
A

Alexei A. Frounze

Mark F. Haigh said:
Alexei A. Frounze wrote:


Oh really? Then where are funcations with external linkage defined?

Exactly what do you mean?
necessary).

Misleading at best. This will generally *not* occur unless the linker
is told to,

It shouldn't be told to. Why linking a module into executable if out of this
module nothing is referenced, neither code nor data? I'd say misleading is
gluing in unuseful code and data.
or the group of object files are made into a static archive
before linking.

I don't know what you mean.
Also, for a discussion about executable sizes to be meaningful, you
have to consider the effect of shared libraries if the system in
question uses them.

Indeed, I did not consider shared libraries in the response, so thank's for
the addition. The original poster didn't mention them, though...
Again, misleading. Depends on the circumstance, and how your linker
handles mutually referential libraries.

I don't know if misleading is one of your favorite self-and-all-explanatory
words... So what if lib1 references lib2 and that one references lib1 back?
Should I get 2 copies of the same code or data (from either lib)? Is that's
what you're saying? I was replying from the size standpoint when saying
*linked once*, I meant getting one instance of say fread() in the executable
and not two or more. I don't know how exactly I should interpret this your
comment, whether you're just uncomfortable with my meaning of "linked once"
and want to tell that the linker will have to go back and forth to resolve
the undefined references in the crossreferencing libraries or want to say
something else but don't say that... If it's the former, then that's
entirely different thing here and to me it has nothing to do with the size
of the code. If it's the latter, then please explain or I'm starting to feel
that your comment is misleading at best too.

Strange. I thought there would be not a single point of agreement. ;)
Not by too much, on today's systems.

Which means you've never been involved in projects whose size and complexity
required more horsepower for compilation than was available. Or you think
everyone's got a today's super computer. Either way this your assertion is
very doubtful.

Alex
 
A

Alexei A. Frounze

pete said:
Why put inline functions in the .h file?

How would you share an inline function between 2 .c files? Except by having
2 copies of it, only through an .h file. Just like a common macros.

Alex
 
A

August Karlstrom

Eric said:
It's easy to declare types with file scope in C: Just Do It.

Yes, you are right (and I was wrong). However, this is an example of an
irregularity in C -- of the declarations

struct s { int m; };
int n;
void f(void);

`struct s' has file scope, but n and f has global scope (require `static').


August
 
E

Eric Sosman

August Karlstrom wrote On 10/05/05 11:44,:
Yes, you are right (and I was wrong). However, this is an example of an
irregularity in C -- of the declarations

struct s { int m; };
int n;
void f(void);

`struct s' has file scope, but n and f has global scope (require `static').

Right. Or more precisely, n and f have file scope
but external linkage. Other modules (sorry, "translation
units") can refer to them, but only by re-declaring them;
n and f are not automatically in scope for other modules.

Ever since I first encountered C in the mid-1970's
I've felt that the language took the wrong default for
"undecorated" declarations at file scope. That is, I
think it would have been better if n and f were "implicitly
static" (in today's terms) and that an identifier would have
external linkage only if declared with a keyword like `public'
or `export'. Obviously, dmr did not feel that way -- and
it's not really a huge problem; I just reflexively put
`static' on nearly everything. The habit is so strong that
even when I'm writing tiny little one-file programs the
only externally-linked identifier I declare is main().
 
M

Mike Wahler

August Karlstrom said:
Yes, you are right (and I was wrong). However, this is an example of an
irregularity in C -- of the declarations

struct s { int m; };
int n;
void f(void);

`struct s' has file scope, but n and f has global scope (require
`static').

I think you need to sort out in your mind the difference between
scope and linkage.

-Mike
 
M

Mark F. Haigh

Alexei said:
Exactly what do you mean?

Functions that are "exposed to the outer world" (external linkage) have
to be defined somewhere. They're declared in the headers, but they are
generally defined in .c files.
It shouldn't be told to. Why linking a module into executable if out of this
module nothing is referenced, neither code nor data? I'd say misleading is
gluing in unuseful code and data.

Like it or not, this behavior is common for a variety of reasons. If
you're building a library, then nearly all the code looks "unused" from
the linker's point of view.
I don't know what you mean.

The semantics of linking against static libraries and object files
differ. Generally speaking, linkers pick and choose from libraries but
include the whole of object files (unless instructed not to). Since
this is very platform-specific (and OT), I'll leave it at that.

I don't know if misleading is one of your favorite self-and-all-explanatory
words... So what if lib1 references lib2 and that one references lib1 back?
Should I get 2 copies of the same code or data (from either lib)? Is that's
what you're saying? I was replying from the size standpoint when saying
*linked once*, I meant getting one instance of say fread() in the executable
and not two or more. I don't know how exactly I should interpret this your
comment, whether you're just uncomfortable with my meaning of "linked once"
and want to tell that the linker will have to go back and forth to resolve
the undefined references in the crossreferencing libraries or want to say
something else but don't say that... If it's the former, then that's
entirely different thing here and to me it has nothing to do with the size
of the code. If it's the latter, then please explain or I'm starting to feel
that your comment is misleading at best too.

Files are often linked more than once. This is commonly known as
partial (or relocatable) linking. Mutually referential libraries need
to be repeatedly linked until there are no further unresolved symbols.
That's why your statment "each library and object file is linked only
once" is incorrect.

Understand that in most cases on non-embedded platforms, there will be
_no_ instances of library code in the executable. There will just be
an undefined symbol that is patched up by the dynamic linker/loader at
run time. To use your example, there would be no instances of fread()
in _any_ executable, one instance of fread() in a shared library, and
all executables use the same instance.

Once again, this is OT, so I will stop there.

Which means you've never been involved in projects whose size and complexity
required more horsepower for compilation than was available. Or you think
everyone's got a today's super computer. Either way this your assertion is
very doubtful.

I regularly deal with the internals of compiling and linking
multi-million line codebases, often distributed across farms of
multi-processor machines. Compilation time of large vs. small C files
do not typically differ by more than a second on any post-Pentium III
machine.


Mark F. Haigh
(e-mail address removed)
 
A

Alexei A. Frounze

Mark F. Haigh said:
Functions that are "exposed to the outer world" (external linkage) have
to be defined somewhere. They're declared in the headers, but they are
generally defined in .c files.

I don't see where this your statement contradicts mine. I might misused some
word (define vs declare or whatever -- forgive my bad English), but that's
what I meant. But I explicitly wrote "externs" in the list below .h -- see
my previous post.

???
Like it or not, this behavior is common for a variety of reasons. If
you're building a library, then nearly all the code looks "unused" from
the linker's point of view.

The original poster asked about "modularization of C programs" meaning that
he's making programs, not libraries. Unless you extend programs to cover
libraries too, this is irrelevant. But I do acknowledge your ... let's look
up the dictionary ... punctiliousness. Or pedantry. Pick whichever you like
better :)
The semantics of linking against static libraries and object files
differ. Generally speaking, linkers pick and choose from libraries but
include the whole of object files (unless instructed not to). Since
this is very platform-specific (and OT), I'll leave it at that.

What do you mean by "the whole of object files"? Do you mean *all* files or
whole files (e.g. a file in whole/entire file)? And unless that particular
linker treats a library as something more special that the collection of the
object files it consists of (for what reason would it?), there is no
difference.
Files are often linked more than once. This is commonly known as
partial (or relocatable) linking. Mutually referential libraries need
to be repeatedly linked until there are no further unresolved symbols.
Right.

That's why your statment "each library and object file is linked only
once" is incorrect.

So, with all your pedantry, can you forgive me my English? :)
Understand that in most cases on non-embedded platforms, there will be
_no_ instances of library code in the executable. There will just be
an undefined symbol that is patched up by the dynamic linker/loader at
run time. To use your example, there would be no instances of fread()
in _any_ executable, one instance of fread() in a shared library, and
all executables use the same instance.

That is all correct.
Once again, this is OT, so I will stop there.

:) I've already suggested not covering the DLLs as there was no inquiry to.
And I've just suggested not making the term library subset of the term
program. To lawyers these would probably the same thing, to us there's a
difference.
I regularly deal with the internals of compiling and linking
multi-million line codebases, often distributed across farms of
multi-processor machines. Compilation time of large vs. small C files
do not typically differ by more than a second on any post-Pentium III
machine.

Then I may only tell you that you're a lucky guy to have all that now and as
maybe all the time before.

Since I'm seeing not much of a disagreement between us, just you being
pedantic, maybe we shall finish this thread right here? I guess the original
poster is already satisfied with the details.

Alex
 
M

Mark F. Haigh

Alexei said:
I don't see where this your statement contradicts mine. I might misused some
word (define vs declare or whatever -- forgive my bad English), but that's
what I meant. But I explicitly wrote "externs" in the list below .h -- see
my previous post.

"Declaration" and "definition" have precise meanings in C. If you
don't understand the difference, look it up.
???


The original poster asked about "modularization of C programs" meaning that
he's making programs, not libraries. Unless you extend programs to cover
libraries too, this is irrelevant. But I do acknowledge your ... let's look
up the dictionary ... punctiliousness. Or pedantry. Pick whichever you like
better :)

Hmmm. You post incorrect information with a false air of authority,
then whine "pedantry!" when corrected. While you have the dictionary
open, look up the word "wanker", as you're starting to become one.

What do you mean by "the whole of object files"? Do you mean *all* files or
whole files (e.g. a file in whole/entire file)? And unless that particular
linker treats a library as something more special that the collection of the
object files it consists of (for what reason would it?), there is no
difference.

Static libraries _are_ different than the collection of object files it
consists of. If you link against a static library, you will not link
in unused object files. If you link against an object file, you will
include everything, whether it's used or not.

<remainder snipped>


Mark F. Haigh
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top