PDA

View Full Version : avoiding double includes while using opengl libraries in object oriented environment?



wildeyedboyfromfreecloud
10-25-2001, 08:42 PM
ok so i'm using ms visual c++. anyhow i've broke my prodject down into multiple files.
ok. so all of my class files need to #include the openGL libraries. but i want all of my individual class objects to have them intrinsically. but i don't want to have a double include in my project. sorry i'm so lazy. but programming isn't my day job. and i'm not sure really where to look for this particular bit of information. i know there is a way to do it. i remember reading it somewhere. anyhow thanks again. i apreciate it. ciao.

Spiral Man
10-25-2001, 09:29 PM
#ifndef GL_H
#define GL_H
#include <GL/gl.h> //or whatever it is
#endif

should work...

wildeyedboyfromfreecloud
10-26-2001, 12:17 AM
thanks, yeah those are the ones.
apreciate much http://www.opengl.org/discussion_boards/ubb/smile.gif

Tron
10-26-2001, 01:24 AM
btw: this is technique called: sentry

you should use it in all your header files, e.g.:

(cSomeClass.h)
#ifndef cSomeClass_h
#define cSomeClass_h
// your code here
#endif

so you can be sure your header files get only included once

Nutty
10-26-2001, 12:23 PM
At my place we make a point of doing gaurd block checks around the include statements themselves in the C/C++ files. This stops the compiler even opening the file, if it has already been included before, vastly improving compile speed. Relying on the gaurd blocks in the headers themselves still forces the compiler to parse the header searching for the resulting #endif.

P.S. Yes I know some systems support pre-compiled headers, but in my experience they are very buggy, and are not available on alot of cross development compiler systems, that I use.

Nutty

Spiral Man
10-26-2001, 03:56 PM
you should still put them in your headers, redundancy is always good, in case you forget...

wildeyedboyfromfreecloud
10-26-2001, 08:58 PM
OK SO as i think i understand it. in "???_H" the syntax doesn't really matter? and the preprocessor just checks to see if any includes in this file are reused? i found the documentation in a reference book. but it wasn't really described in detail. sorry i just can't tell completely what is going on from looking at sample files that utilize the techniques. sorry i'm really not making much sense of it. and i'm a completely rational sensible kinda guy. anyone who wants to elaborate a little bit i'd apreciate it much. thanks everyone btw


[This message has been edited by wildeyedboyfromfreecloud (edited 10-26-2001).]

Tron
10-26-2001, 11:09 PM
if you have a header file you can prevent it from beeing included multiple times (and generating multiple-declaration errors) by using a sentry.




#ifndef TOKEN

checks if this token is defined, if not processes the code between the #ifndef and the matcihng #endif
the name of the token isn't important, but it's good coding style to name it as the header file. this way you prevent accidently using the same token in multiple headerfiles.
e.g.: if your header file has the name "Types.h" then you should use the token Types_h




#define TOKEN

if the token wasn't defined (meaning the header file isn't included yet), define it now.

next you put all your code into the header file...




#endif

that's simply the #endif for the preceeding #ifndef

hope that helps (:

wildeyedboyfromfreecloud
10-26-2001, 11:33 PM
that was my line of thought. but so then, everytime the header file is mentioned then you should supply the sentry format? well for all of your auxilary files. and then not in the main routine? sorry is there a good place in the ms visual C help docs that covers working within the workspaces in detail. i know that all this can be done through the command line in like unix but. anyhow c++ books don't go into detail about managing multiple files. am i being a strain. i hope not. thanks.

MikeC
10-28-2001, 02:51 AM
Originally posted by Spiral Man:
#ifndef GL_H
#define GL_H
#include <GL/gl.h> //or whatever it is
#endif

should work...

Not quite.

ALL quality header files will wrap their entire contents with multiple-include guards, like so:

#ifndef foo_h
#define foo_h
// all class/function/etc declarations here
#endif

So you should never get compile-time errors, even if you write something like:

#include <GL/gl.h>
#include <GL/gl.h>

The technique of having extra guards OUTSIDE of the header files in question was first widely publicized by John Lakos in his excellent book "Large-Scale C++ Software Design", and it's only a means to reduce compilation times. Nothing to do with program correctness, and for small projects (under 10 or 20 thousand lines) it's not so important.

The point of these external guards is this: while the internal guards prevent errors, the compiler still has to read in the header file every time it's #included, and has to parse the whole file looking for the #endif at the end. For big projects, avoiding these redundant reads can be a big win. Microsoft has the (obviously non-portable) #pragma once, which does much the same thing, and some other compilers are bright enough to notice when an entire header is wrapped in an #ifndef/#endif and skip redundant includes automatically.

The #defined token names used by these guards are completely arbitrary; usually they're based on the filename, but they aren't mandated anywhere and may well be different in gl.h files from different vendors. The problem with Spiral Man's posted snippet is that he has the #define before the #include. So if gl.h is using GL_H for its internal guards (which is quite a likely choice), and you've already #defined it before the #include, the contents of gl.h will never get included AT ALL.

The absolutely bulletproof version looks like this:

#ifndef GL_H
#include <GL/gl.h>
#undef GL_H
#define GL_H
#endif

(The #undef is to cope with the remote possibility that gl.h has #defined GL_H to be a value - it's an error to re-#define a token with a different value.)

In practice, you're usually fine with a mangled token, e.g.

#ifndef INCLUDED_EXTERNAL_GL_H
#include <GL/gl.h>
#define INCLUDED_EXTERNAL_GL_H
#endif

You *might* get very very unlucky, but the compiler will tell you if you do.


HTH
Mike

wildeyedboyfromfreecloud
10-28-2001, 05:26 AM
so tell me please? you should do this for every instance of a header file? so say you have 4 headers? then you have 4 statements for each for a total of sixteen statement. with the file ending in
#endif
#endif
#endif
#endif

or do you only do it once when you create the file. which would me library files such as gl.h should already be ready to cope with it?

MikeC
10-28-2001, 05:57 AM
Originally posted by wildeyedboyfromfreecloud:
so tell me please? you should do this for every instance of a header file? so say you have 4 headers? then you have 4 statements for each for a total of sixteen statement. with the file ending in
#endif
#endif
#endif
#endif

or do you only do it once when you create the file. which would me library files such as gl.h should already be ready to cope with it?


I think you're getting confused. Or maybe I'm confused by what you mean by "instance of a header file".

For each header file YOU write, you have ONE set of INTERNAL guards - one #ifdef-#define-yourstuff-#endif block inside each header file. Library headers like gl.h will have this already, yes, so you don't need to do anything for them.

When you're using extra EXTERNAL guards to speed up compilation, you have one set of guards around each #include directive. These guards are ONLY around the #include, not the whole file. Probably a couple of examples are easier (indentation is just to show scoping and doesn't affect semantics):

Example 1: foo.h without external guards



#ifndef INCLUDED_FOO_H

#define INCLUDED_FOO_H

#include "GL/gl.h"
#include "myfile.h"

class Foo {};

#endif


Example 2 : foo.h with external guards



#ifndef INCLUDED_FOO_H
#define INCLUDED_FOO_H

#ifndef INCLUDED_GL_H
#include "GL/gl.h"
#undef INCLUDED_GL_H
#define INCLUDED_GL_H
#endif

#ifndef INCLUDED_MYFILE_H
#include "myfile.h"
#endif

class Foo {};

#endif


Note that in the second example there's no #define in the external guards around myfile.h - this is your file, so you can choose the name of the internal guard to match:




// myfile.h
#ifndef INCLUDED_MYFILE_H
#define INCLUDED_MYFILE_H
// whatever
#endif


To be honest, I'd suggest you skip the external includes until you have a better understanding of C/C++ and are writing larger projects that will benefit from it. The much simpler pattern shown in example 1 is fine for small projects.


[This message has been edited by MikeC (edited 10-28-2001).]

wildeyedboyfromfreecloud
10-28-2001, 06:41 AM
thanks i follow it totally now. i just like to have a solid understanding of what is going on. i have a thurough understanding of C++ but not much experience admitedyly. there isn't really much to just knowing the compilier. anyhow i'm not very familiar with the libraries. its only that i haven't been able to find any thorough documentation on this subject. i was defining large classes that referenced each other. i'm working with openGL. which is new to me for the most part. though i understand computer graphics theory but i'm trying to take advantage of openGL because of its multi platform functionality and because it is a standard. anyhow blah blah. i'm only a programmer once a month so. in the end. thanks i really apreciate it.

pythagoras
10-29-2001, 07:35 AM
One more small point: make sure you #define a term which is unlikely to be #defined in any other headers. You don't want your header excluded because someone else already #defined your term.

For example,
#ifndef MATRIX_H
#define MATRIX_H
.
.
.
#endif // MATRIX_H
would probably be a bad idea.

HTH G.