Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Question regarding Order of Include directives

Status
Not open for further replies.

pghsteelers

Technical User
Apr 21, 2006
121
0
0
US
I am having a hard time understanding how to make sure that the #include directives are listed in the correct order as it is to my understanding.

Is there a way that daily programmers use to help sort out one needing to come before another in the header files?
 
If the program is written well, it shouldn't matter what order you include files.
One common mistake that people run into is forgetting the guard directives in their header files. For example, to make sure that your header file isn't included multiple times in the same module, do something like this in the header file:
Code:
#ifndef SOME_BIG_LONG_STRING_OF_RANDOM_JUNK
#define SOME_BIG_LONG_STRING_OF_RANDOM_JUNK

// Put all your header code here.

#endif // SOME_BIG_LONG_STRING_OF_RANDOM_JUNK
The "random junk" should be different for each header file you have. If you let Visual Studio create it for you, you'll see something like this:
Code:
#if !defined(AFX_REGISTRY_H__AC6FFAD9_7CCC_4465_9D91_409BA4BD201F__INCLUDED_)
#define AFX_REGISTRY_H__AC6FFAD9_7CCC_4465_9D91_409BA4BD201F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// Your class definition...

#endif // !defined(AFX_REGISTRY_H__AC6FFAD9_7CCC_4465_9D91_409BA4BD201F__INCLUDED_)
 
I thought that was what "#pragma once" is supposed to do?
 
To my understanding #progma once macro is suppose to do that. However, why does every book and tutorial that I go through emphasize the order of the headers.

I haven't even heard before that there is a way to write code thats note *broken* so that you can put your headers in any order.
 
Well, either #pragma once works or it doesn't. I always like to think that the people who write the compiler know what they're doing. But maybe I'm overoptimistic!
 
#pragma once is a MS Visual C++ specific directive. If you want your code to be portable across all compilers, use the header guard directives instead.

I'm not sure why your book is emphasizing the order of your #include directives? There are very few C header files that were designed using an old idea that required you to #include one file before another, but I almost never run into those kinds of problems. The new design mentality is to make all your header files as self reliant as possible.
 
The only header I know of that matters is stdafx.h, which is a visual studio specific header used for the pre-compiled headers feature. That should always be first in the source file if you are using pre-compiled headers. Otherwise, the headers can generally be included in any order.
 
Someone else mentioned that writing code so it isn't *broken*, allowing #include directives to be included in any order since back in the conception of C. I had mentioned in response that in numerous tutorials/books that I have read I hadn't heard any mentioning of such practice, but quite the opposite.

Since this practice is suppose to have been around since before version 6 of VC, I found a reference in Ivan Hortons (Beginning Visual C++ 6) which has been mentioned by numerous programmers as a "very good book".

He mentions as example when taking you through one of the programs that he walks you through:

"Because the handler declares a CPenDialog object, you must add a #include statement for PenDialog.h to the beginning of SketcherDoc.cpp (after the #includes for stdafx.h and Sketcher.h), otherwise you'll get compilation errors when you build the program."

So, is what I am hearing now, that these teachers are teaching a wrong practice of defining .h files? Or am I missing. Again, this is just an example of the continuous taught method for all .h files in his book.
 
I have that book. Let me know the page number and I'll take a look when I get home.
 
I think you are misunderstanding that statement. In my interpretation, it means that the compilation errors will occur if you don't add the #include statement for PenDialog.h to the beginning of SketcherDoc.cpp (in whatever order you place it).

The parenthetical reference to placing it after stdafx.h is necessary for the reason I mentioned above that is specific to stdafx.h, and I highly doubt the reference to placing it after Sketcher.h was meant to be absolute. The author was probably just mentioning that for clarity or consistency.

I don't think the author would disagree with the responses you've received in this thread.

An example of what those headers define or another reference to a similar statement might make it more clear.
 
There are several schools of thought here. Say C.h depends on B.h and A.h. D.h depends on A.h.

One school of thought - no header file should include any other header file. This is just rubbish for maintenance but I know lots of developers (who normally don't want to maintain 'old' code) who will argue that it is easier to understand.

Another school of thought is that you should include all dependent header files first. This is the normal cause of broken builds.

For both those systems, the following would work

source C.c
#include "A.h"
#include "B.h"
#include "C.h"

source D.c
#include "A.h"
#include "D.h"

If we now change dependencies such that A.h depends on B.h, the changes are

source C.c
#include "B.h"
#include "A.h"
#include "C.h"

source D.c
#include "B.h"
#include "A.h"
#include "D.h"

All the source files have to be changed. If you forget about a file E.c which depends on "D.h", you have a broken build. These may be recommended methods but they are difficult to maintain. You will find that those who recommend these methods don't normally hang around after the project is finished. Someone else has to maintain their mess.

Another school of thought, which happens to be my preferred one, is to include all the files required by a header in a header.

source C.c
#include "C.h"

source D.c
#include "D.h"

source C.h
#include "A.h"
#include "B.h"

source D.h
#include "A.h"

If the dependencies change, we ony have to modify A.h

source A.h
#include "B.h"

Nothing else needs to change. If E.c depends on D.h, it won't break the build. Putting C.h as the first include file ensures that C.h is no dependent on anything else that it hasn't already included. In pghsteelers example, Sketcher.h would be included inside PenDialog.h: not after it. Recommended methods are like recipes. They are just a guideline: not a hard and fast rule. They don't work for everyone in every situation.

In very large projects, it is a lot easier to include header files in any order. It is easy to maintain specific orders on small projects but such practices are near impossible to enforce/police on large projects with tens of developers. When you have to do code walkthroughs/reviews of 50K+ lines, and a project manager breathing down your neck, having include files in a specific order won't be at the top of your list.

Think about it: does it make any difference whether you have

#include <fstream>
#include <iostream>

or

#include <iostream>
#include <fstream>

Why? because the relevant files have already been included in iostream and fstream.

#pragma once is a Microsoft special: all pragmas are vendor specific. It will work as long as you are in a specific MS environment. Once you get outside that environment, you'll get problems. Even going from one MS compiler to another, pragmas can get added or withdrawn. I find that it is safer to use #ifndef ... #define ... #endif than to rely on #pragma once. #pragma once did not exist on MSC 5.0 (circa 1988: not VS5.0) so if I tried compiling code on that compiler, it would probably moan a lot and might even fall over.
 
OK, I'll accept the portability issue. But remember, if you choose to be ultra-portable and never use any specific microsoft features, you're going to have to spend a lot of time coding wheels that microsoft coded years ago and provided as tools.

The other problem is human psychology in our cut-and-paste world. When you choose a guard header with a long and random define, some creative thinker will come along a few years later and use your header (complete with exactly the same long and random define!) as a template for a new header altogether in the same project, and wonder why it all goes horribly wrong.
 
lionhill said:
When you choose a guard header with a long and random define, some creative thinker will come along a few years later and use your header (complete with exactly the same long and random define!) as a template for a new header altogether in the same project, and wonder why it all goes horribly wrong.
He'll also wonder why the rest of the developers in his group are laughing at him... :)
Then he won't make that mistake again.
 
When you choose a guard header with a long and random define, some creative thinker will come along a few years later and use your header (complete with exactly the same long and random define!) as a template for a new header altogether in the same project, and wonder why it all goes horribly wrong.

thats why i use the date and hour in my #if !defined.. etc

#if !defined(JULY_THIRTEEN_TWO_THOUSAND_SIX_TWENTY_TWO_FORTY_SIX_SOMERANDOMLETTERS_)

chuck in your name, DOB, and your pretty much guaranteed a unique string

If somethings hard to do, its not worth doing - Homer Simpson
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top