Jump to content

  • Log In with Google      Sign In   
  • Create Account


Header Files


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 GameCreator   Members   -  Reputation: 656

Like
0Likes
Like

Posted 30 June 2013 - 09:14 PM

Very beginner question but how the heck do header files work?

 

I'm using RakNet and have a cpp file with a bunch of functions using it and its variables.  Works great.  Then I made a function which was declared (?) in a .h file, as per below:

 

int getplayernumberfromguid(RakNetGUID id);

 

I then get a TON of "error C2065: 'RakNetGUID' : undeclared identifier" errors for the same line.

 

So, I figure, in my infinite wisdom: no problem - I'll just copy and paste the #include stuff from the top of the cpp file into the top of the h file.  If it works for one, it should work for the other.  Well, that just brings in a mess of new errors including errors inside the RakNet files which should have no issues whatsoever.

 

Any idea what I'm doing wrong?  How are you really supposed to do this?

 

Thanks in advance!



Sponsor:

#2 Bacterius   Crossbones+   -  Reputation: 7990

Like
1Likes
Like

Posted 30 June 2013 - 10:25 PM

Can you post every source/header file relevant to the problem (provided it's not too long)? It's hard to follow exactly what you did and what you could have done wrong.


The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#3 Trienco   Crossbones+   -  Reputation: 2043

Like
8Likes
Like

Posted 30 June 2013 - 10:25 PM

Ah, surprisingly I am often amazed that even many "professional" programmers have no idea how this works in detail. There will be a big step back to explain the two phases of making an executable.

 

Compiling: every .c/.cpp/.cc (whatever your source files are called) is compiled in complete isolation. It knows absolutely nothing about the content of any other source file. This will usually create one compiled object file for every source file.

 

Linking: this pieces together all the object files into one big executable binary. This is also the step where every function that is being called must exist in one (and exactly one) object file (or one of the linked libraries). Same goes for global or static member variables.

 

Another important distinction is "declaration" vs. "definition". A header should usually contain only declarations (or inline code). Declarations say "this thing exists somewhere", while a definition says "this right here IS the thing". For global variables, "extern" is used to tell a declaration from a definition. For functions this difference is having or not having a function body.

 

 

So headers are a) never compiled on their own and b) are completely irrelevant for linking. They are needed to be able to compile source files that are using or referencing stuff that is "somewhere else". However, these are only declarations. Also, linker errors will never ever be fixed by touching #includes (except maybe by removing them if your compiler is seriously trying to link stuff that is never actually used).

 

There is also the issue of circular includes. If your includes ever start going around in circles, this is a bug and no, inclusion guards have nothing to do with it and won't fix that. The only solution is to not them and use forward declarations to break them up (using forward declarations as much as possible in header files is generally preferable anyway, especially when it comes to compile times). This is also one big reason why not to spam includes all over the place in header files, just in case they _might_ be needed or out of sheer convenience (my favorite quote from a coworker "but this is way easier, so everyone including this header automatically gets all the other stuff".. uhm, yes, including all the stuff they don't need, that might result in conflicts and will blow up compile times by a few multitudes).

 

 

So random guesses:

-your header includes something, but not RakNetTypes.h

-your header is trying to include itself

-the header isn't found and you are not looking at the error messages starting at the top

-there is a typo in the identifier


f@dzhttp://festini.device-zero.de

#4 GameCreator   Members   -  Reputation: 656

Like
0Likes
Like

Posted 30 June 2013 - 11:00 PM

Thank you very much Trienco.  That actually clearly taught me quite a bit!  Here are the two relevant files.

 

networking.cpp

http://pastebin.com/PGpfVf9d

 

networking.h

http://pastebin.com/1Q77HBdZ

 

The latest change I made was trying to put

int getplayernumberfromguid(RakNetGUID id);

at the bottom of the h file to declare it, if that's the right word.  That's when this mess started.  If I declare it at the top of the cpp file then it all works.

 

By the way, I did also noticed that RakNetGUID is declared in RakNetTypes.h and I tried adding that too but it makes no difference.  Plus it was never needed for my cpp file so maybe it's declared or linked to in another h file??  Don't know.

 

My other guess is that it may have something to do with:

using namespace RakNet;

Not sure how that works across various files but including it in the h file didn't seem to help.

 

I may be over my head with this.  I'm still a little confused as to how what I'm doing could possible start generating errors in RakNet's code (which I didn't touch).

 

(As as sidenote, it's a little intimidating to know that at any time my code can break because I don't know enough and at one point maybe it'll be too complex for anyone to help.)



#5 Bacterius   Crossbones+   -  Reputation: 7990

Like
6Likes
Like

Posted 30 June 2013 - 11:25 PM

Okay, first,

anything that starts with an underscore is reserved for the C/C++ implementation. Do not use such identifiers if it can be avoided (I mean the header guard).

 

Secondly, yes - what is happening is that you've put all the includes in the source file. But those headers aren't going to be visible from networking.h, since it's the header that's included inside the source file and not the opposite. So what happens is you now have a source file loaded with #include's (which are then only usable from inside this source file, unless you are including .cpp files somewhere) and a header which now has no idea what RakNetGUID is since it includes no header files from RakNet (it only includes "MessageIdentifiers.h" which I assume only contains.. well.. message identifiers, and isn't the header that is telling your program what RakNetGUID is. I don't know RakNet but I suppose it would be in some header that you included in the .cpp file.

 

So what you need is to locate that header (refer to the documentation) and move that #include to your header file networking.h. It needs it to be able to understand what you meant by the "RakNetGUID" type name.

 

Also, if the same header is included both in networking.h and networking.cpp, you can delete the #include from the .cpp (source) file - since that file includes your networking.h header, the #include will appear twice in that case which is redundant.

 

In general:

in your header file: include the absolute minimum needed to declare all the types you refer to in your function declarations, classes, and so on.

in your source file: include everything you need, except what is already in the corresponding header

 

The reason you don't include everything in the header is because you want your headers to:

A) be self-contained (they must work without needing to have the user include anything else)

B) impose no constraints on the user of the header

 

There are a few recent GameDev articles about how #include's work exactly and how to use them as effectively as possible, have you taken a look? They should be in the "general programming" articles section.


Edited by Bacterius, 30 June 2013 - 11:29 PM.

The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#6 GameCreator   Members   -  Reputation: 656

Like
0Likes
Like

Posted 01 July 2013 - 09:35 AM

Thank you much!  That sounds promising.  Will try it when I get home.

 

Also, it took me a second to find the article mentioned.  It's here for convenience: http://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r3173


Edited by GameCreator, 11 July 2013 - 11:20 PM.


#7 GameCreator   Members   -  Reputation: 656

Like
0Likes
Like

Posted 02 July 2013 - 12:11 AM

I haven't read the article yet but I moved all but network.h includes to the header.  Now I get a bunch of redefinition errors, like so:

 

1>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\ws2def.h(91): warning C4005: 'AF_IPX' : macro redefinition
1>          C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\winsock.h(460) : see previous definition of 'AF_IPX'
1>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\ws2def.h(131): warning C4005: 'AF_MAX' : macro redefinition
1>          C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\winsock.h(479) : see previous definition of 'AF_MAX'
1>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\ws2def.h(168): warning C4005: 'SO_DONTLINGER' : macro redefinition
1>          C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\winsock.h(402) : see previous definition of 'SO_DONTLINGER'
1>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\ws2def.h(212): error C2011: 'sockaddr' : 'struct' type redefinition
1>          C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\winsock.h(485) : see declaration of 'sockaddr'
1>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\ws2def.h(390): error C2059: syntax error : 'constant'
1>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\ws2def.h(390): error C3805: 'constant': unexpected token, expected either '}' or a ','

etc.

 

I'll have to reread these posts to get a better understanding and probably that article.

(I assume, by the way, that having two cpp files include network.h isn't an issue...)


Edited by GameCreator, 02 July 2013 - 12:13 AM.


#8 Tribad   Members   -  Reputation: 787

Like
0Likes
Like

Posted 02 July 2013 - 03:00 AM

Only include winsock2.h

 

no ws2def.h

 

Its some time back that I created windows applications. But I think you can even ignore windows.h because it is included somewhere deep inside the winsock2.h

 

Anyways winsock2.h must be included before windows.h



#9 GameCreator   Members   -  Reputation: 656

Like
0Likes
Like

Posted 02 July 2013 - 08:50 AM

I don't have those includes in my code but RakNet does (and it's smart enough to know which goes first).  However, I'm using a second library which uses windows.h.  So... by moving the headers, is there a chance that their order got switched?  Because it was working before and all I did was move the headers from my network.cpp to my network.h (which is included in at least 2 cpp files).


Edited by GameCreator, 02 July 2013 - 08:51 AM.


#10 Tribad   Members   -  Reputation: 787

Like
0Likes
Like

Posted 03 July 2013 - 04:08 AM

Think about two different scenarios.

 

A library/subsystem creator who has defined a lot of structures that need a specific order is the responsible that wants to make the usage, and thus the inclusion of headers, as easy as possible. This is why you find system header include statements in other include files. This makes the usage for the library function as easy as possible.

 

System-Header files are enclosed in <>.

 

The developer of a system/subsystem does not include his own header files from within header files, to have a better control about what is included within a single source files. Circular includes or other problems with undefined or double defined structures/defines and the like can be overcome if the application includes are only put into the source.

 

Application specific header files are enclosed in "".

 

Using <> or "" has todo with the search order of the pre-processor for include files.

 

Another thing is that pre-processor and compiler are two different things. The pre-processor creates a stream of text that results of processing any #directive. The compiler processes that stream after that processing has done. You can tell the compiler to only make the pre-processing step an put the result into a file/stdout. This way you can investigate the the order of files that are included and what the result of the pre-processing is.

 

Think of a define you made different to some system header file. You will not find the bug without have a look on the input stream to the compiler.

 



#11 Sunda   Members   -  Reputation: 330

Like
0Likes
Like

Posted 03 July 2013 - 09:46 AM

Think about two different scenarios.

 

A library/subsystem creator who has defined a lot of structures that need a specific order is the responsible that wants to make the usage, and thus the inclusion of headers, as easy as possible. This is why you find system header include statements in other include files. This makes the usage for the library function as easy as possible.

 

System-Header files are enclosed in <>.

 

The developer of a system/subsystem does not include his own header files from within header files, to have a better control about what is included within a single source files. Circular includes or other problems with undefined or double defined structures/defines and the like can be overcome if the application includes are only put into the source.

 

Application specific header files are enclosed in "".

 

Using <> or "" has todo with the search order of the pre-processor for include files.

 

Another thing is that pre-processor and compiler are two different things. The pre-processor creates a stream of text that results of processing any #directive. The compiler processes that stream after that processing has done. You can tell the compiler to only make the pre-processing step an put the result into a file/stdout. This way you can investigate the the order of files that are included and what the result of the pre-processing is.

 

Think of a define you made different to some system header file. You will not find the bug without have a look on the input stream to the compiler.

 

This is very interesting i really didn't know what was behind the compiling process, can you recommend a couple of books about this kind of topics?



#12 Tribad   Members   -  Reputation: 787

Like
0Likes
Like

Posted 03 July 2013 - 12:28 PM

Öh.

I learned this about 30 years ago. It is part of any C/C++ compiler description. On unix-style machines and I think on solaris as well the C pre-processor is a separat program cpp named and you will find descriptions on the man-pages.

 

I never used books to learn things. So I cannot recommend one.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS