header files

Get answers to all your basic programming questions. No Ogre questions, please!
a_ht
Gnoblar
Posts: 7
Joined: Sun Jul 17, 2005 2:14 am

header files

Post by a_ht »

Is there a compiler keyword that prevents the compiler from indefinetaly looping trough your header files because they include each others?

For example; I have the three following header files; h1.h, h2.h, h3.h

h1.h

Code: Select all

#include "h2.h"
h2.h

Code: Select all

#include "h3.h"
h3.h

Code: Select all

#include "h1.h"
main.cpp

Code: Select all

#include <stdio.h>
#include "h1.h"

int main()
{
printf("Hello room");
}
The compiler will indefinitly try to include the header files into themselves until it is stopped.
User avatar
:wumpus:
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3067
Joined: Tue Feb 10, 2004 12:53 pm
Location: The Netherlands
x 1

Post by :wumpus: »

yes, it's called include file armouring, you can see it being done in all of the Ogre include files:

Code: Select all

#ifndef __GLPIXELFORMAT_H__
#define __GLPIXELFORMAT_H__
/// Rest of file here

#endif
__GLPIXELFORMAT_H__ is a unique string for this file.

Best is of course to just not have circular includes, but this prevents it from crashing your compiler at least.
User avatar
:wumpus:
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3067
Joined: Tue Feb 10, 2004 12:53 pm
Location: The Netherlands
x 1

Post by :wumpus: »

preferably don't use #pragma once, it isn't part of the official C++ standard so isn't portable
User avatar
SuprChikn
Bugbear
Posts: 863
Joined: Tue Apr 19, 2005 6:10 am
Location: Melbourne, Aus
Contact:

Post by SuprChikn »

@friend_of_ACCU: please read the existing replies before you make your own...

@a_ht: circular includes may cause more problems later on (not always I dont think). You may also want to look into "forward declaration".
It has been talked about on these forums a bit before. Try this topic for instance.
User avatar
skullfire
Gremlin
Posts: 150
Joined: Sat Mar 19, 2005 7:51 pm
Location: San Jose, Costa Rica
Contact:

Post by skullfire »

:wumpus: wrote:preferably don't use #pragma once, it isn't part of the official C++ standard so isn't portable
plus, only vsstudio
I may have alzheimer, but at least I dont have alzheimer.
User avatar
DaesDemon
Goblin
Posts: 209
Joined: Thu Jan 22, 2004 3:59 pm
Location: Toulouse (France)

Post by DaesDemon »

IIRC VS has some macro predefined to write the #ifdef #def #endif for you.
At least it had in VC6.

Or you can define them a least relativly easily ;)
Every Night and every Morn
Some to Misery are born.
Every Morn and every Night
Some are born to Sweet Delight,
Some are born to Endless Night.
User avatar
Feral
Halfling
Posts: 80
Joined: Thu May 26, 2005 9:12 pm
Location: NORTHERN California, USA

Post by Feral »

I use both, as I understand it "#pragma once" saves a bit of parsing time (compiler just skips the rest of the file rather than reading to the #endif) so I use it when I can, and make sure there is a proper fallback for when "#pragma once" is not available.

Below is an example:
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef macHeader_FERALFILEHEADER_vim
#define macHeader_FERALFILEHEADER_vim

// TODO: code goes here...

#endif // EO: ifndef macHeader_FERALFILEHEADER_vim
//
/// EOF
Below is an the relivent .vim: (Rather abrevated as the original file is is 8k)

Code: Select all

if exists("loaded_feralfileheader")
	finish
endif
let loaded_feralfileheader = 1

let s:save_cpo = &cpo
set cpo&vim
function s:FeralFileGuard() "{{{

	let DaFile = expand("%:p:t:r")
	" Use Luc's idea of \W, tis better than my original \\.!
	let DaInclude_GATE = substitute(DaFile, "\W", "_", "g")
	" TODO Text for DaInclude_GATE should be configurable!
	let DaInclude_GATE = "macHeader_".toupper(DaInclude_GATE)."_".tolower(expand("%:e"))

	let Was_Reg_z = @z

	let @z = ""
	if has("win32")
		let @z = @z."#if _MSC_VER >= 1000\n"
		let @z = @z."#pragma once\n"
		let @z = @z."#endif // _MSC_VER >= 1000\n"
	endif
	let @z = @z."#ifndef ".DaInclude_GATE."\n"
	let @z = @z."#define ".DaInclude_GATE."\n"
	let @z = @z."\n"
	let @z = @z."#endif // EO: ifndef ".DaInclude_GATE."\n"
	let @z = @z."//\n"
	let @z = @z."/// EOF\n"

	put z
	let @z = Was_Reg_z
	unlet Was_Reg_z
endfunction
"}}}
command				FFGUARD			:call <SID>FeralFileGuard()
let &cpo = s:save_cpo
"EOF
Just in case it might be of use to someone. (=
User avatar
:wumpus:
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3067
Joined: Tue Feb 10, 2004 12:53 pm
Location: The Netherlands
x 1

Post by :wumpus: »

Feral wrote:I use both, as I understand it "#pragma once" saves a bit of parsing time (compiler just skips the rest of the file rather than reading to the #endif) so I use it when I can, and make sure there is a proper fallback for when "#pragma once" is not available.
Not true for modern compilers, as they recognize the 'guard' construction used and associate it with the filename of the .h. When it is included for a second time, it isn't even parsed.
User avatar
:wumpus:
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3067
Joined: Tue Feb 10, 2004 12:53 pm
Location: The Netherlands
x 1

Post by :wumpus: »

Obviously it is parsed first time, both in the #ifdef case and the pragma case. Otherwise there would be little reason for the file to be included in the first place. You're probably confused with "#pragma never" :-)
bstrr
Halfling
Posts: 56
Joined: Wed Jul 13, 2005 2:01 pm

Post by bstrr »

if you're a real compile-speed freak you can take it further:

Code: Select all

#ifndef _STRING_
  #include <string>
#endif
that way it won't even open the file just to discover, that it shouldn't parse it :)
User avatar
Feral
Halfling
Posts: 80
Joined: Thu May 26, 2005 9:12 pm
Location: NORTHERN California, USA

Post by Feral »

Oh that is neat to know, certainly would be the intelligent thing to do from a compiler standpoint I guess.

It has been quite some time (VC5 era) since I read the docs on "#pragma once" so I thought it wise to dig it up:
Specifies that the file will be included (opened) only once by the compiler in a build. This can reduce build times as the compiler will not open and read the file after the first #include of the module.
I have to wonder how the compilers deal with a include guard mid way in the file (for whatever reason) when the user wants half of the file to be parsed?

*shrug* As the adage goes, if it works, use it! ;)
User avatar
:wumpus:
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3067
Joined: Tue Feb 10, 2004 12:53 pm
Location: The Netherlands
x 1

Post by :wumpus: »

friend_of_ACCU wrote: I mean, in #pragma once case its parsed until #pragma once encountered
The #ifdef construction, like #pragma once, is detected on the first parsing of the .h header file. In both cases, the filename of the .h is stored in the compiler has "already included". They effects are identical. End of discussion, really, search some mailing lists about compilers if you want to know how it's done in detail.
bstrr
Halfling
Posts: 56
Joined: Wed Jul 13, 2005 2:01 pm

Post by bstrr »

I think friend_of_accu is thinking of a case, where you only #ifdef "part of a file" - but that's got nothing to do with #pragma once :)
User avatar
Game_Ender
Ogre Magi
Posts: 1269
Joined: Wed May 25, 2005 2:31 am
Location: Rockville, MD, USA

Post by Game_Ender »

friend_of_ACCU wrote:effect is the same but #ifndef requires more parsing.
Is that one extra line really worth it? The compiler can take note of where the #endif is on the first parse, eliminating the need to reparse the file. So as far as the compiler is concerned:

Code: Select all

#pragma once  = #ifndef _MYFILE_H
                #define _MYFILE_H
(As Already stated)
The is really just an informal test from this article, but it does indicate that if build speed is your preference you don't want to be using the VC++ compiler in the first place. I do recommend the site linked from above, it has some good articles on game development.

Code: Select all

The Results
System 	Compiler 	Platform 	Full build   Incremental   Incremental lib
Vis.Studio VC++       Windows XP 	7m 28s 	 0m 54s 	    0m 4s
Make 	   g++ 	    Linux 	     2m 21s 	 0m 2.4s 	   0m 0.0s
Jam 	    g++ 	    Linux 	     2m 42s 	 0m 1.6s 	   0m 0.1s
Jam 	    VC++ 	   Windows XP 	6m 52s 	 0m 3.1s 	   0m 0.3s
Scons 	  g++ 	    Linux 	     5m 31s 	 1m 02s 	    0m 16s
Scons 	  VC++ 	   Windows XP 	8m 02s 	 0m 55s 	    0m 8s
EDIT: Make that the Visual Studio compiler (VC++) or build system.
bstrr
Halfling
Posts: 56
Joined: Wed Jul 13, 2005 2:01 pm

Post by bstrr »

What's the speed/size of the code produced?
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Post by jacmoe »

It's not the compiler, it's the preprocessor. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
Game_Ender
Ogre Magi
Posts: 1269
Joined: Wed May 25, 2005 2:31 am
Location: Rockville, MD, USA

Post by Game_Ender »

He doesn't comment, but the point of the article was to find a build system that allowed you to make a little change in the code and see the effect in a couple of seconds. Since he is a professional game developer he might use something like Intel's compiler for final releases where speed matters. Which would probably mean he isn't that concerned with the speed of the code produced. After all that I haven't heard much about there being a huge speed difference.

EDIT:Jacome, Isn't the prepocessor part of the compiler?
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Post by jacmoe »

IIRC, the preprocessor prepares the source code for the compiler.
If you write some crappy code, and writes this:

Code: Select all

#ifdef 0
// crappy code
#endif
Your compiler doesn't see the crappy code.
And that gives us an excellent opportunity to save some compiler energy:
To avoid compiling large portions of commented out code, consider using #ifdef 0 instead.

Macros is also a preprocessor *thing* - and that makes them not very safe to use. The compiler doesn't know what happens.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
haffax
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4823
Joined: Fri Jun 18, 2004 1:40 pm
Location: Berlin, Germany
x 7
Contact:

Post by haffax »

I have to disagree here. #ifdef 0 is no good way to comment things out.

First it isn't obvious. Comments make it blatantly clear that something is commented out. The IDE and most advanced editors have syntax higlighting and they highlight comments too. But few if none highlight the code between #ifdef 0 / #endif as inactive or commented.

Second there is no advantage, as comments are also handled by the preprocessor.
team-pantheon programmer
creators of Rastullahs Lockenpracht
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Post by jacmoe »

haffax wrote:I have to disagree here. #ifdef 0 is no good way to comment things out.
I agree - merely explaining the preprocessor.
I am not using #ifdef 0's myself for the very same reasons. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
Post Reply