Rob Pike's simple Include rule

B

Ben Pfaff

Christian Bau said:
I prefer the rule that

#include "header.h"

as the first line in a source should compile without error for every
header file, and that changing the order of "#include"s should not make
any difference.

Personally, I recently began enforcing this rule in my own code
by making every file.c include its own file.h as its very first
#include. (I got this suggestion from _Large-Scale C++ Design_,
if I recall correctly.)
 
P

Peter Nilsson

Neil Cerutti said:
Oops.

3. What is the average air-speed velocity of an unladen sparrow?

<OT>

The Bridgekeeper in Monty Python and the Holy Grail actually asks...

What... is the air-speed velocity of an unladen swallow?

</OT>
 
K

Keith Thompson

Mark McIntyre said:
Keith, when you can find me a sparrow that can fly continuously for a
fortnight, I;ll go with your figure rather than CBF's...

When you successfully argue in traffic court that you weren't really
driving 80 miles/hour because you were only doing it for 10 minutes,
I'll take that argument seriously. (Convert units as necessary for
non-US traffic courts.)

However ...
since when were sparrows swallows? :)

I acknowledged my error elsethread.

"This is getting silly." -- Graham Chapman
 
M

Mark Piffer

It's a nightmare for both the implementor and the user. Consider
things like size_t and NULL, that are supposed to be available in
several headers: if the implementor wants to change one of them, he
must take care to change *all* the headers defining/declaring the
identifier in question.


If you see the following in a header:

void foo(FILE *);

then this header implicitly states that <stdio.h> must be included first.

I guess Pike was either drunken or stoned when he suggested that the
users of a header actually read the header in order to figure out its
dependencies.

Dan

I didn't read Pike's original statements but I guess I am exposed to
an even stricter style guide: within a client company of mine there is
the rule that every header file has to have an "PRIVATE" section which
defines (not declares!) all file-global objects. Below there needs to
be a "PUBLIC" (or EXTERN, I don't remember) and a "COMMON" section
which declare the respective "purely extern" objects which are
exported by this module (whatever that means) and the shared objects.
Yes, I am still talking C, though the creator admits that his
construct is influenced by a C++ class definition. For a clearer idea
let me picture a typical header file as it is required to be:
foo.h (accompanying header file to foo.c)

typedef int bar; // common section for all
#ifdef _PRIVATE
#undef _PRIVATE
// used inside foo.c
bar Global;
bar foo(void);
#else
// used outside of foo.c
extern bar Global;
extern bar foo(void);
#endif

foo.c has to include foo.h as the last header file, with a preceding
#define _PRIVATE

And yes, the "no include includes others"-rule is in effect too.
Aside from the bad but sometimes inevitable global variables, I
consider this style ultimately evil, but I lack the proper verbal
ammunition to sink it. Anyone who can help with a list of unbeatable
arguments against it?

Mark
 
N

Neil Cerutti

<OT>

The Bridgekeeper in Monty Python and the Holy Grail actually asks...

What... is the air-speed velocity of an unladen swallow?

</OT>

I apologize for being a dodo and cocking up the joke.
 
A

Alan Balmer

This is untrue. I know of no make tool (gnu, ms, or otherwise) that will
take it upon itself to examine your code for dependencies.

makedepend. While it may not be the same executable as make (and then
again, it may be), it's part of the same tool chain and closely
integrated, and no one actually cares what executable it's in, so long
as it does its job.
 
X

Xenos

makedepend. While it may not be the same executable as make (and then
again, it may be), it's part of the same tool chain and closely
integrated, and no one actually cares what executable it's in, so long
as it does its job.
--
Al Balmer
Balmer Consulting
(e-mail address removed)

makedepend is not part of make. Its a tool separate tool (and not part of
any "tool chain") use to modify existing makefiles to add target
dependencies to the end of the file. Modify the makefile is not something
I'd recommend. I'd much prefer someithing like:
http://make.paulandlesley.org/autodep.html.

Someone will care if they need a separate tool, like makedepend, automake,
etc., to build your software and they don't have it.


DrX
 
N

Nick Landsberg

[SNIP first instance of signature line]
makedepend. While it may not be the same executable as make (and then
again, it may be), it's part of the same tool chain and closely
integrated, and no one actually cares what executable it's in, so long
as it does its job.

Agreed Alan,

On a project a long, long time ago, we got bit.
Started using "makedepend", but, as usual, some
developers forgot and the same problems occurred.
We found a version of "make" out of Bell-Labs
research which actually subsumed the functionality
of makedepend. It was called "nmake", I believe,
and it is still used on many a project. I believe
it is available (for a price), to folks on the
outside. So, whether it's called makedepend, or
integrated into the functionality of "make" does not
matter. As you say, as long as it does it's job
 
I

Irrwahn Grausewitz

Alex Monjushko said:
It is perfectly legal as long as the leading underscore is not
followed by an upper-case character.

It's not.

ISO/IEC 9899:1999
7.1.3 Reserved identifiers
1 [...]
- All identifiers that begin with an underscore are always reserved
for use as identifiers with file scope in both the ordinary and
tag name spaces.

Regards
 
D

Dan Pop

In said:
It is perfectly legal as long as the leading underscore is not
followed by an upper-case character.

Is it?

- All identifiers that begin with an underscore are always
reserved for use as identifiers with file scope in both the
ordinary and tag name spaces.

This basically limits the usage of such identifiers to block local
variables. Why bother at all?

Dan
 
C

CBFalconer

Mark said:
.... snip ...

I didn't read Pike's original statements but I guess I am exposed
to an even stricter style guide: within a client company of mine
there is the rule that every header file has to have an "PRIVATE"
section which defines (not declares!) all file-global objects.
Below there needs to be a "PUBLIC" (or EXTERN, I don't remember)
and a "COMMON" section which declare the respective "purely
extern" objects which are exported by this module (whatever that
means) and the shared objects. Yes, I am still talking C, though
the creator admits that his construct is influenced by a C++
class definition. For a clearer idea let me picture a typical
header file as it is required to be: foo.h (accompanying header
file to foo.c)

typedef int bar; // common section for all
#ifdef _PRIVATE
#undef _PRIVATE
// used inside foo.c
bar Global;
bar foo(void);
#else
// used outside of foo.c
extern bar Global;
extern bar foo(void);
#endif

foo.c has to include foo.h as the last header file, with a
preceding #define _PRIVATE

And yes, the "no include includes others"-rule is in effect too.
Aside from the bad but sometimes inevitable global variables, I
consider this style ultimately evil, but I lack the proper
verbal ammunition to sink it. Anyone who can help with a list
of unbeatable arguments against it?

Uqh. To start with, it is a complete misuse of header files,
which should be used solely to expose the appropriate portions of
the .c file.

Anything private can be made so by the simple (and defined) use of
the word 'static'. This also makes maintenance easier, because
there is no need to look for occurences outside the .c file.
 
W

-wombat-

Neil said:
1. Is following this guideline facile or hassle? I converted a
simple two-header program over to this style, making several
errors along the way. I clearly don't have experience
with it.

It's more of a hassle, but for a really good reason: Each time a header file
is read, disk I/O is incurred. Even if you put header guards to prevent
multiple definition, there's still disk I/O involved in reading the header
file (even if it's in the kernel's cache.)

Yes, things get complicated with forward definitions and various types of
dependencies between headers. But any acyclic graph can be reduced to a
tree.

Once upon a time, though, disk buffers were a premium, so extraneous disk
I/O really had a time cost penalty associated with it. Today, it's not so
bad. But Pike's premise is still a relatively good idea (despite Bob
Tisdale's wanks to the contrary.) If it's good enough for BSD headers, it's
probably just a really good idea.


-scooter
 
E

E. Robert Tisdale

-wombat- said:
It's more of a hassle, but for a really good reason:
Each time a header file is read, disk I/O is incurred.
Even if you put header guards to prevent multiple definition,
there's still disk I/O involved in reading the header file
(even if it's in the kernel's cache.)

Nonsense!
A good C preprocessor remembers the names of idempotent header files
and won't even open much less read them a second time.
Yes, things get complicated with forward definitions
and various types of dependencies between headers.
But any acyclic graph can be reduced to a tree.

Once upon a time, though, disk buffers were a premium, so
extraneous disk I/O really had a time cost penalty associated with it.
Today, it's not so bad.
But Pike's premise is still a relatively good idea
(despite Bob Tisdale's wanks to the contrary.)
If it's good enough for BSD headers,
it's probably just a really good idea.

No. It's a bad idea.
Check out, for example, the GNU C preprocessor
> info cpp 'Header Files' 'Once-Only'
The GNU C preprocessor is programmed to notice when a header file
uses this particular construct and handle it efficiently. If a header
file is contained entirely in a `#ifndef' conditional, then it records
that fact. If a subsequent `#include' specifies the same file, and the
macro in the `#ifndef' is already defined, then the file is entirely
skipped, without even reading it.

If your C preprocessor does not implement this optimization,
it's time to shop around for a better C compiler.
 
W

-wombat-

E. Robert Tisdale said:
-wombat- wrote:
No. It's a bad idea.
Check out, for example, the GNU C preprocessor

Not on all versions. That's a 3.x enhancement. Not all of us can u/g or use
3.x at the moment.
The GNU C preprocessor is programmed to notice when a header file
uses this particular construct and handle it efficiently. If a header
file is contained entirely in a `#ifndef' conditional, then it records
that fact. If a subsequent `#include' specifies the same file, and the
macro in the `#ifndef' is already defined, then the file is entirely
skipped, without even reading it.

Not on gcc 2.95.4, it doesn't. :)
If your C preprocessor does not implement this optimization,
it's time to shop around for a better C compiler.

Sometimes, Bob, we have to work with what we have, not what we wish we had.
Of course, the discussion becomes moot if headers can be precompiled and
mmap-ed into the compiler's address space (like what the Digital Mars
Compiler does.)


-scooter
 

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
474,141
Messages
2,570,817
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top