I've been fighting with my compiler for too long.
Problems with circular includes, redefinitions, "missing ';' before *" and so on.
This seems like the place to get a good answer.
How do I include everything into everything else, and never have to worry about the subtleties of includes ever, ever again?
What combination of #DEFINE, #pragma, #include, or whatever else do I need to do to ensure that data types in the murky depths of my project hierarchy will have no difficulty knowing what anything else is?
This is not a troll post, incase such a concept is entirely unthinkable, nor is it posted in the middle of being angry.
I'm simply curious as to whether or not such a possibility exists. Dealing with spaghetti includes is probably the biggest headache I have to deal with in C++, and getting rid of it would increase my workflow significantly.
Cheers,
Brian
Forward deceleration in the headers and inclusions in the implementation (.c, .cpp, etc).
Good question. I would like to know how to do this, too. Here's some of my tricks:
Figuring the file hirechary structure (which file use which file) to draw a raw concept graph.
Using the following code structure is helpful for prevent RE-DEFINING. Details can be found here.
#ifndef MY_CLASS
#define MY_CLASS
#endif
It means if the file is already included, it will not be included again.
in the beginning of every header file,
#ifndef __MYHEADER_H__
#define __MYHEADER_H__
in the end,
#endif /* __MYHEADER_H__ */
can avoid contain a header file repeatedly.
if you use visual stuido, you can just put
#pragma once
in the beginning of header file.
By the way, you can use some static code check tool to find these kinds of issues, such as lint.
Related
Maybe I'm thinking about this the wrong way because I spent so many years on C# away from C++ and I'm a bit rusty. I forget how good selective linking is.
This is really a multi-part question, and I'll start by describing the big picture.
I am building a JSON parser and query engine for low memory environments like IoT devices. They don't have a ton of space for code so I want the end developer to be able to only include parts of my library they intend to use. The pull parser is the core of the library so that's a given, but you might not need the in-memory trees.
Currently, lacking a better way, I have a #define HTCW_JSONTREE which i define in one header. It gets picked up by a 2nd header and a function is included in the 2nd header that depends on code in the first header.
#include "JsonTree.h" // optional
#include "JsonReader.h" // if JsonTree.h above is included
// extra functionality will be available from JsonReader
basically a parseSubtree() function that returns an in-memory tree will be available if you include both headers, but won't if you don't include JsonTree.h. It smells.
First of all, is this necessary, or can I just unconditionally include all the functionality and expect that parseSubtree() will never get linked in if its never used?
Second, if it is necessary, what is a better way to do it? Right now the includes are order dependent and the code reeks. I want to change it. Basically it's just in there now until I figure out something better because it's easier to remove than it would have been to add later if it turns out i need it.
Thanks in advance.
Here's more of what the code looks like:
From JsonTree.hpp by way of JsonTree.h:
#ifndef HTCW_JSONTREE_HPP
#define HTCW_JSONTREE_HPP
#define HTCW_JSONTREE
#include <cinttypes>
...
from JsonReader.hpp by way of JsonReader.h:
#ifdef HTCW_JSONTREE
JsonElement* parseSubtree(mem::MemoryPool& pool,JsonParseFilter* pfilter = nullptr,mem::MemoryPool* pstringPool=nullptr,bool poolValues=false) {
...
#endif
Where JsonElement comes from JsonTree.h as well. parseSubtree is my integration point between the two areas of functionality
First of all, is this necessary
Absolutely not.
Or can I just unconditionally include all the functionality and expect that parseSubtree() will never get linked in if its never used?
You totally can. That's how all libraries in existence have worked from day one.
I'm trying to teach myself C++ and one small detail that I don't understand keeps bugging me. I understand the need for header guards but I don't understand the exact syntax. For example. If I have a header file called MyHeader.hpp and I wanted to include it without guards I would write
#include "MyHeader.hpp"
However, all the tutorials I've looked at seem to indicate the way to do this with guards would be something like
#ifndef MYHEADER_HPP
#define MYHEADER_HPP
My question is how does MYHEADER_HPP in the #ifndef/#define equate to the actual file name "MyHeader.hpp" in the original include statement?
Thanks
You could use anything as your define and it would give the same result. The thing to look out for is if you would use the same name in two different files, you would get a problem if you try to include both in the same translation unit.
A very easy way to avoid that is to use header guards that matches the filenames.
The code I am working has multiple headers and source files for different classes face.cc, face.hh, cell.cc, cell.hh edge.cc edge.hh and the headers contain includes like this,
#ifndef cellINCLUDED
#define cellINCLUDED
#ifndef faceINCLUDED
#define faceINCLUDED
I saw through http://www.cplusplus.com/forum/articles/10627/ and saw the way to write include guard is
#ifndef __MYCLASS_H_INCLUDED__
#define __MYCLASS_H_INCLUDED__
So in above code that I am working on, does compiler automatically understands it is looking for face.hh or cell.hh files?
better question : Is writing __CELL_H_INCLUDED__ same as cellINCLUDED ?
#ifndef __MYCLASS_H_INCLUDED__
#define __MYCLASS_H_INCLUDED__
So in above code that I am working on, does compiler automatically
understands it is looking for face.hh or cell.hh files?
No, the compiler doesn't automatically understand what you mean.
What really happens is that, when compiling a translation unit, the Compiler holds a list of globally defined MACROs. And so, what you are doing is defining the MACRO __MYCLASS_H_INCLUDED__ if it doesn't already exists.
If that macro is defined, that #ifndef until #endif will not be parsed by the actual compiler.
Hence you can test for the existence of that MACRO to determine if the Compiler has parsed that header file to include it once and only once in the translation unit... This is because the compiler compiles each translation unit as one flattened file (after merging all the #includes)
See https://en.wikipedia.org/wiki/Include_guard
Is writing __CELL_H_INCLUDED__ same as cellINCLUDED ?
Yes it is.... The reason some prefer using underscored prefixed and suffixed MACROs for include guards is because they have extremely low probability of ever being used as identifiers... but again, underscore could clash with the compiler...
I prefer something like this: CELL_H_INCLUDED
If you use cellINCLUDED, there are chances that someday, somebody may use it as an identifier in that translation unit
The preprocessor definitions have no special meaning. The only requirement is that they stay unique across the modules, and that's why the file name is typically a part of them.
In particular, the mechanics for preventing double inclusion aren't "baked in" the language and simply use the mechanics of the preprocessor.
That being said, every compiler worth attention nowadays supports #pragma once, and you could probably settle on that.
As the link you have referenced says, "compilers do not have brains of their own" - so to answer your question, no, the compile does not understand which particular files are involved. It would not even understand that '__cellINCLUDED' has anything conceptually to do with a specific file.
Instead, the include guard simply prevents the logic contained between its opening #ifndef and closing #endif from being included multiple times. You, as the programmer, are telling the compiler not to include that code multiple times - the compiler is not doing anything 'intelligent' on its own.
Nope, This is essentially telling the compiler/parser that if this has already been put into the program, don't puthave already been loaded.
This should be at the top (and have an #endif at the bottom) of your .h file.
Lets say you have mainProgram.cpp and Tools.cpp, with each of these files loading fileReader.h.
As the compiler compiles each cpp file it will attempt to load the fileReader.h. unless you tell it not to it will load all of the fileReader file in twice.
ifndef = if not defined
so when you use these (and the #endif AFTER all your code in the .h file)
you are saying:
if not defined: cellINCLUDED
then define: cellINCLUDED with the following code:
[code]
end of code
so this way when it goes to load the code in your .h file a second time it hits the if not defined bit and ignores the code on the second time.
This reduces compile time and also means if you are using a poor/old compiler it isn't trying to shove the code in again.
I am used to putting header guards around my objects like:
#ifndef SOMETHING_H
#define SOMETHING_H
class Something {
...
}
#endif
but I have been given code where they also do:
#ifndef SOMETHING_H
#include "something.h"
#endif
for every include. Supposedly, this is better. Why? Is this redundant with guards around the object?
This is discussed in pretty good detail here:
http://c2.com/cgi/wiki?RedundantIncludeGuards
Here are the highlights:
Yes this is redundant, but for some compilers it may be faster because the compiler will avoid opening the header file if it doesn't need to.
"Good compilers make this idiom unnecessary. They notice the header is using the include-guard idiom (that is, that all non-comment code in the file is bracketed with the #ifndef). They store an internal table of header files and guard macros. Before opening any file they check the current value of the guard and then skip the entire file."
"Redundant guards have several drawbacks. They make include sections significantly harder to read. They are, well, redundant. They leak the guard name, which should be a secret implementation detail of the header. If, for example, someone renames the guard they might forget to update all the places where the guard name is assumed. Finally, they go wrong if anyone adds code outside of the guard. And of course, they are just a compile-time efficiency hack. Use only when all else fails."
The thinking behind it is the preprocessor will not need to open the header file and read the contents to determine that that header has been previously included, thus saving some time during compilation. However, most compilers these days are already smart enough to spot multiple inclusions of the same file and ignore subsequent occurrences.
It's good to have this on header and class definition files, so that on compilation, if a file is referenced in a loop (a.cpp references a.h and b.cpp, and b.cpp also references a.h, a.h will not be read again) or other similar cases.
The case that worries me most about what looks like your question is that the same constant name is being defined in different files, and possibly preventing the compiler from seeing some necessary-to-see constants, classes, types, etc. as it will "believe" that the file was "already read".
Long story short, put different #ifndef constants in different files to prevent confusion.
The purpose of doing this is to save on compile time. When the compile sees #include "something.h", it has to go out and fetch the file. If it does that ten times and the last nine all basically amount to:
#if 0
...
#endif
then you're paying the cost of finding the file and fetching it from disk nine times for no real benefit. (Technically speaking, the compiler can pull tricks to try and reduce or eliminate this cost, but that's the idea behind it.)
For small programs, the saving probably aren't very significant, and there isn't much benefit to doing it. For large programs consisting of thousands of files, it isn't uncommon for compilation to take hours, and this trick can shave off substantial amounts of time. Personally, it's not something I would do until compilation time starts becoming a real issue, and like any optimization I would look carefully at where the real costs are before running around making a bunch of changes.
I've copied and pasted some files from my windows machine to my linux one and ran into a few understandable problems with the conio.h and Windows.h headers, but I can't remember what they're needed for.
They're only in the main function so I commented them out and ran the program again thinking the errors would show me where they're needed so I could then google what headers would work similarly for linux.
The problem I have is that all the errors I get are in header files I've included in the main function, but don't have the Windows.h or conio.h headers included.
The question I have is how/why: -
Does the compiler look at each header file in turn, get to the windows.h header and stop then when that's commented out it get's to my "Chapter_7.h" header and find all the problems in there.
Or could the commenting out of the headers in the main.cpp somehow affect the headers I wrote.
Or (possibly more likely) Is there another option I've overlooked?
Thanks for any answers.
It is due to the way .h files are "INCLUDED" in the .cpp. During compilation, all the text in the header files is copy pasted into the including .cpp file. This means later .h files will have access to earlier ones.
This looks to be what is happening in your case, windows.h would have been the first include, and subsequent headers have been using it all along.
//#include <window.h>
//#include <conio.h>
#include "myheader.h" // can no longer use windows.h or conio.h
#include "myheader2.h"
You can say header contents are copy-pasted inside the file they're included in, if that's what you mean.
Or could the commenting out of the headers in the main.cpp somehow affect the headers I wrote.
Definitely. Assume:
//header1.h
#define X 1
//header2.h
#ifdef X
int a = 0;
#else
int a = 1;
#endif
a will be defined differently if header1.h is included before or after header2.h.
The first step of fixing "I'm using headerfiles that I can't use on this machine" is to remove those files, compile the code and see where things break - it's nearly always making compiler errors, so you should be able to find it quite easily.
conio.h allows console io, and it may require a bit of work to fix that into Linux. Depends on exactly what you are using.
windows.h is much more complex to explain, as it essentially gives you all of the Windows API functions, and a huge number of type declaration, and there are many of those. Most of which your program probably never uses [directly].
One of the common problems with "using a headerfile that doesn't exist somewhere else" is that you end up using some types that are declared in the headerfile. So for example, windows.h will declare LONG, HANDLE, and a vast number of other types. These types are then used in structures and function declarations elsewhere, and when you remove windows.h it will cause all manner of follow-on problems.
My approach is always to fix the first problem first, then compile again. The reason for this is that the compiler often gets "confused" if something strange appears. It's a bit like if you were to tell a friend how to drive to your house, and you say "When you see the big-oaktree on the left, you take the next right". Unknown to you, the oak-tree has been cut down because it was dieing, and is no longer there. So your friend drives where the oak-tree used to be, and turns right after another oak-tree later on along the road. Of course, now all OTHER instructions are completely uselss, because your friend is miles away from the correct road, and is never going to find your house without new instructions. The same thing happens when the compiler finds "surprising" or "missing" bits in the source-file. So fixing the first error, then compiling, fixing, compiling, usually gets you to a point where your code compiles. Sometimes this involves writing new functions like this:
int GetTimeOfDay(void)
{
printf("%s:%d:%s: doesn't work yet, exiting...", __FILE__, __LINE__, __func__);
exit(1);
return 0; // to keep compiler happy.
}
Once you got all the code compiling, you start working out how to implement/replace those functions that you added to make it compile.