#includes in header files

M

Mark

Hello

I once read that it's not a good programming style to #include in header files, where structs, typedefs or functions are declared. Just to illustrate:

/* foo.h */
#ifndef FOO_H
#define FOO_H

extern int foo1(int, int);
extern double foo2(double, double);

#endif

/* foo.c */
#include "foo.h"
/* here to include any other necessary headers */

int foo1(int x, int y)
{
...
}

double foo2(double x, double y)
{
...
}

What to do if, say, a function declared has one of parameters of type 'size_t'. This type is defined in stddef.h, so incusion of this file is inevitable:

/* foo.h */
extern void foo3(char *, size_t);
...

Is there a common way to workaround this, or it is perfectly well to have file included in the headers?

Thanks.

--
Mark
 
S

Spiros Bousbouras

Hello

I once read that it's not a good programming style to #include in header files, where structs, typedefs or functions are declared. Just to illustrate:

/* foo.h */
#ifndef FOO_H
#define FOO_H

extern int foo1(int, int);
extern double foo2(double, double);

#endif

/* foo.c */
#include "foo.h"
/* here to include any other necessary headers */

int foo1(int x, int y)
{
...

}

double foo2(double x, double y)
{
...

}

What to do if, say, a function declared has one of parameters of type 'size_t'. This type is defined in stddef.h, so incusion of this file is inevitable:

/* foo.h */
extern void foo3(char *, size_t);
...

Is there a common way to workaround this, or it is perfectly well to have file included in the headers?

For size_t I would put inside foo.h
#include <stddef.h>

I think it's perfectly acceptable programming style.
 
N

Nate Eldredge

Mark said:
Hello

I once read that it's not a good programming style to #include in
header files, where structs, typedefs or functions are declared.

I would disagree. Do you recall where you read this, and what
justification was given?

[...]
What to do if, say, a function declared has one of parameters of type
'size_t'. This type is defined in stddef.h, so incusion of this file
is inevitable:

/* foo.h */
extern void foo3(char *, size_t);
...

Is there a common way to workaround this, or it is perfectly well to
have file included in the headers?

I would include <stddef.h> into foo.h. I see no reason not to.

The other alternative would be to document that foo.h requires that
stddef.h be included first.
 
M

Mark

Nate Eldredge said:
I would disagree. Do you recall where you read this, and what
justification was given?
It was in this group approximately 3 years back, can't remember who was advocating this.

If you don't mind - what are your pros about including standard header files in to programmer-defined headers?

--
Mark
 
N

Nate Eldredge

It was in this group approximately 3 years back, can't remember who
was advocating this.

If you don't mind - what are your pros about including standard header
files in to programmer-defined headers?

Mainly that it makes the file self-contained, so the user doesn't have
to keep checking the documentation for what other headers they need (and
what headers *they* need, and so on). This is at least an annoyance,
and occasionally a source of obscure bugs if some are omitted.

Arguments about namespace pollution would seem to be a red herring,
since the user will have to include the relevant header anyway. Perhaps
there is something to be said for the fact that this would force the
user to *recognize* that pollution, but IMHO it doesn't compensate for
the trouble.
 
N

Nate Eldredge

Richard Heathfield said:
Mark said:


Idempotency, for a start. Incidentally, I've changed my mind on
this. Ten years ago, I was in the "don't nest headers" school of
thought, mostly because I had my eye on nesting limits. In
practice, however, these are only ever approached by the curious
student and the terminally insane, and making a header stand alone
has real benefits for code maintenance.

These limits were also lower ten and twenty years ago. (Anyone remember
having to do FILES=40?)
 
S

Spiros Bousbouras

It was in this group approximately 3 years back, can't remember who was advocating this.

If you don't mind - what are your pros about including standard header files in to programmer-defined headers?

Let's say that the library needs 5 standard headers and you need to
use the library in 10 source files. If those 5 standard headers do
not appear inside your_library.h then you need to include these 5
headers in each of those 10 source files in addition to including
your_library.h. If you modify the library so that for example it
needs 1 additional header then you need to add this additional
header in each of those 10 source files. On the other hand if
your_library.h already includes the 5 standard headers then the
code which uses the library only needs to include your_library.h in
order to be able to use the library. If you modify the library so
that it needs one additional header you do not need to include
anything extra to the source of the files using the library, you
just add the additional header to your_library.h
 
J

jbode

Hello

I once read that it's not a good programming style to #include in header files, where structs, typedefs or functions are declared. Just to illustrate:

[snip]

Is there a common way to workaround this, or it is perfectly well to have file included in the headers?

Thanks.

I think it's better style to let the header include whatever it needs
than to force the programmer to keep track of those dependencies in
the implementation files. If foo.h defines an interface that requires
something from bar.h, then foo.h should go ahead and include it,
rather than forcing the programmer to keep track of that dependency in
his .c files. It's really frustrating to spend an hour or so trying
to figure out which headers need to be included and in what order
because there's NO DOCUMENTATION ANYWHERE describing their
dependencies and you have to grovel through each one to find out.
 
B

Beej Jorgensen

Mark said:
Is there a common way to workaround this, or it is perfectly well to
have file included in the headers?

Here's another vote for allowing includes in header files, for reasons
other people have stated.

-Beej
 
R

Richard Bos

Mark said:
SGVsbG8NCg0KSSBvbmNlIHJlYWQgdGhhdCBpdCdzIG5vdCBhIGdvb2QgcHJvZ3JhbW1pbmcgc3R5
bGUgdG8gI2luY2x1ZGUgaW4gaGVhZGVyIGZpbGVzLCB3aGVyZSBzdHJ1Y3RzLCB0eXBlZGVmcyBv

Mijn luchtkussenvoertuig zit vol paling.

Richard
 
N

Nate Eldredge

christian.bau said:
"idempotency" is the property that it makes no difference whether you
include a file once, twice or more often (but including it zero times
is different). For example,

#include <stdio.h>

does exactly the same thing as

#include <stdio.h>
#include <stdio.h>

FWIW, the term "idempotent" comes from mathematics. If * is some sort
of multiplication operation, an object A is said to be idempotent if
A * A = A.

As a simple example, the 2x2 matrix
/ 1 0 \
\ 0 0 /
is idempotent (under matrix multiplication).

Often A is some sort of operator or function, and * is composition. In
which case idempotent means "doing A twice is the same as doing A once",
which is the sense relevant to us.

I believe the etymology is from "idem" meaning "same" and "potent"
meaning "power": any power of A (i.e. A^n = A * A * ... * A) is equal to
A itself.

A related term is "nilpotent", which is an A such that A * A = 0.
Probably the closest analogy in C would be

#ifdef MYHEADER_H__
#error You already included me
#else
#define MYHEADER_H__
void func(void);
/* more declarations */
#endif
 
P

Phil Carmody

Richard Heathfield said:
Spiros Bousbouras said:


The word might reasonably be substituted by "self-reliance".

Let's take a solid example. If I have a header like this:

#ifndef H_ROPE
#define H_ROPE 1

struct rope_
{
char *data;
size_t curlen;
size_t maxlen;
};

typedef struct rope_ rope;
/* function defs go here */
#endif

when I #include it into a source file:

#include "rope.h"

I get a diagnostic message because size_t is not defined. To fix
this, I have to do something along the lines of:

#include <stddef.h>
#include "rope.h"

which is tedious if done in many places. Easier:

#ifndef H_ROPE
#define H_ROPE 1

#include <stddef.h>

struct rope_
{
char *data;
size_t curlen;
size_t maxlen;
};

typedef struct rope_ rope;
/* function defs go here */
#endif

This way, it's possible to:

#include "rope.h"

without having to pull in stddef manually.

Voila - idempotency.


But that's not what idempotency means at all, to a mathematician.
Idempotency is the equality between doing once and doing more than
once. You're attempting to contrast something more like doing once
with doing partially.

Phil
 
P

Phil Carmody

Richard Heathfield said:
Phil Carmody said:


Fair enough. I just looked up "idem", and it turns out not to mean
what I thought it meant. What you mean by it (which I will
cheerfully accept as the proper meaning) is obviously an important
concept (so important that everybody already has a word for it
except - up until now - me). But the concept I have described is
also important. Is there already a word for it, or do we need to
coin one?

One way I've seen such self-sufficiency described is that the
..h file itself can be compiled. Not sure how to condense that
down to just a word.

Phil
 
N

Nick Keighley

One way I've seen such self-sufficiency described is that the
.h file itself can be compiled. Not sure how to condense that
down to just a word.

I worked on a project where it was compulsary (you couldn't check
it into configuration control) for a header file to compile
"standalone". A dummy .c file was used for the compilation.
 
N

Nate Eldredge

There's a gotcha with that, if you take it literally.
Sorry, I don't have a single word for it either.

A file consisting entirely of blank lines or comments isn't guaranteed
to compile since it would result in an empty object file with no
external definitions (I'm probably expressing this poorly). Standard
C doesn't require such a file to compile. On many compilers it works
anyway.

It isn't guaranteed to compile, because 6.9 (1) requires a translation
unit to consist of at least one external *declaration* ("external" in
the sense of "at file scope"). It need not be a definition, or contain
anything that would produce code or symbols in an object file. Each of
the following is, AFAICT, a correct translation unit:

void foo(void);

enum { BAR, BAZ };

typedef int xyzzy;

On my system, each of these produces an object file with no symbols,
whose only contents are an entry in a section called ".comment" which
records the compiler version. (An empty source file does the same.)

So stdio.h by itself should be a valid translation unit. Of course, the
standard doesn't define what it means for a file to "compile," but on
many implementations, a valid translation unit can be compiled into an
object file (.o or .obj), though it cannot be linked into an executable
if it does not contain a defintion of `main'. In this sense I think
stdio.h would be required to "compile."

I am curious why empty translation units would have been excluded from
the standard, since usually computer scientists are conscientious about
including trivial cases rather than excluding them. I don't think it
can have been to avoid "empty" object files, because as we see above,
legal translation units need not actually generate any code or data, or
define or reference symbols. The Rationale doesn't seem to speak to
this directly; I didn't see anything relevant in the discussion of 6.9.
The only relevant occurence of the word "empty" was the following
passage regarding 6.7 (Declarations):

The C89 Committee decided that empty declarations are invalid, except
for a special case with tags (see sec. 6.7.2.3) and the case of
enumerations such as enum{zero,one}; (see sec. 6.7.2.2). While many
seemingly silly constructs are tolerated in other parts of the
language in the interest of facilitating the machine generation of C,
empty declarations were considered sufficiently easy to avoid.

Empty declarations might be easy to avoid, but a translation unit
containing no declarations at all seems like it might reasonably be
generated by some program (e.g. a translator for a language that does
accept empty source files). In practice, the easiest way to circumvent
this is probably to include a superfluous declaration like one of the
above examples in the output unconditionally, which is a bit of a wart.
 
J

jameskuyper

Nate Eldredge wrote:
....
It isn't guaranteed to compile, because 6.9 (1) requires a translation
unit to consist of at least one external *declaration* ("external" in
the sense of "at file scope"). It need not be a definition, or contain
anything that would produce code or symbols in an object file. Each of
the following is, AFAICT, a correct translation unit:

void foo(void);

enum { BAR, BAZ };

typedef int xyzzy;

An external definition is defined as "an external declaration that is
also a definition of a function
(other than an inline definition) or an object." (6.9p5). None of your
examples defines either a function or an object.
 
N

Nate Eldredge

jameskuyper said:
Nate Eldredge wrote:
...

An external definition is defined as "an external declaration that is
also a definition of a function
(other than an inline definition) or an object." (6.9p5). None of your
examples defines either a function or an object.

That's true, but the standard does not require a translation unit to
contain an external definition, as far as I can tell; only an external
declaration.
 
J

jameskuyper

Nate said:
That's true, but the standard does not require a translation unit to
contain an external definition, as far as I can tell; only an external
declaration.

Sorry - for some reason (possibly the fact that the section title was
"External definitions"), I misread "external declaration" in 6.9p1 as
"external definition". That's what comes from being in a hurry.
 
K

Keith Thompson

Nate Eldredge said:
That's true, but the standard does not require a translation unit to
contain an external definition, as far as I can tell; only an external
declaration.

Correct. C99 6.9p1:

Syntax

translation-unit:
external-declaration
translation-unit external-declaration

external-declaration:
function-definition
declaration
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top