471,319 Members | 1,613 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,319 software developers and data experts.

multiple inclusion of header file

5
Hello,

I am new to C++, coming from a background in Java and procedural languages. I am currently translating some code from Java to C++ as an exercise and have run into the following problem:

File a.h contains some constant definitions.
As a protection against multiple definitions of these constants I included the following lines at the top of it:
#ifndef const_file_def
#define const_file_def
and added at the end:
#endif

The classes defined in files b.h/b.cpp and c.h/c.cpp both need these definitions and therefore #include a.h
The class defined in files d.h/d.cpp makes use of both b and c classes, and so is compiled as follows:
c++ -o d.out d.cpp b.o c.o
where b.o and c.o were created earlier with a c++ -c command.
The problem is that despite my #ifndef clause at the top of a.h I still get a "multiple definition of " error for every constant defined in it.

How can I avoid the multiple definitions?

Many thanks,

Abe
Aug 16 '07 #1
6 12043
Banfa
9,065 Expert Mod 8TB
File a.h contains some constant definitions.
As a protection against multiple definitions of these constants I included the following lines at the top of it:
#ifndef const_file_def
#define const_file_def
and added at the end:
#endif
This is the right thing to do.

The class defined in files d.h/d.cpp makes use of both b and c classes, and so is compiled as follows:
c++ -o d.out d.cpp b.o c.o
where b.o and c.o were created earlier with a c++ -c command.
The correct format for compiling d.cpp would be

c++ -o d.out d.cpp

The compiler really has no interest in other objects, that is the relem of the linker.

The problem is that despite my #ifndef clause at the top of a.h I still get a "multiple definition of " error for every constant defined in it.
From your description I would suggest looking for a typo in the structure of you preprocessor statements in
Expand|Select|Wrap|Line Numbers
  1. #ifndef const_file_def
  2. #define const_file_def
  3.  
  4. // Definitions here
  5.  
  6. #endif
  7.  
Aug 16 '07 #2
javan
5
Many thanks. The "typo" was in fact a misunderstanding on my part: all of my constants were defined as instance variables, i.e., lacking the keyword "const". Once I introduced this keyword in front of all of them the compilation was successful because they were all inlined and referenced only once in the code.

One word about the linking: I understand that the C++ compiler as such is not interested in object files created earlier, but by default my compiler first compiles and then proceeds to link, so omitting the *.o files from the command line causes it to report a whole host of undefined references. Obviously I need the linker to run as well if I want to be able to run the resulting *.out file. Or am I again missing something?

Thanks,

Abe
Aug 16 '07 #3
Banfa
9,065 Expert Mod 8TB
One word about the linking: I understand that the C++ compiler as such is not interested in object files created earlier, but by default my compiler first compiles and then proceeds to link, so omitting the *.o files from the command line causes it to report a whole host of undefined references. Obviously I need the linker to run as well if I want to be able to run the resulting *.out file. Or am I again missing something?
Nope that sounds about right to me, many compilers proceed to run the linker as well unless you tell them not to.
Aug 16 '07 #4
weaknessforcats
9,208 Expert Mod 8TB
lacking the keyword "const". Once I introduced this keyword in front of all of them the compilation was successful because they were all inlined and referenced only once in the code.
What is happening is not what you think.

Each time a header file is included, its contents are processed. If you create variables, then each time you include the header, the variables are created again. Hence redefinition at the compiler level.

So, you do the #ifndef and the errors from the compiler go away only to be replaced by redefinition errors from the linker. This is caused by including the header file in multiple source files. The compiler sees only one file. The linker sees them all.

So, you add const and all the errors go away. Unfortunately, what does not go away are all the variables. They have still been multiply created but the const tells the linker they can only be used in the file where they were defined.

So, if you have 5000 files in your program that include this header you have 5000 sets of variables.

Solution: Do not create variables in header files.

Header files are for declarations not definitions. A declaration says a thing exists. A definition uses the declaration to create the object.

What you should do is:

In the header, declare the variables as extern. That says the variables are in another file and are sharable (external linkage). LIke this:

Expand|Select|Wrap|Line Numbers
  1. //header.h
  2. extern const int MAX;
  3. extern const in MIN;
  4.  
Then in one source file, create the variables:

Expand|Select|Wrap|Line Numbers
  1. //app.cpp
  2. extern const int MAX = 100;
  3. extern const int MIN = -100;
  4.  
Normally, constants have internal linkage so they are not sharable in other files. That is the default when you create them. The example above just overrides the default and makes the constant sharable.

Later, you can learn to not use global variables at all. However, one thing at a time.
Aug 16 '07 #5
javan
5
Many thanks for the detailed explanation. I fully agree that global variables are not a good idea - but this is not what I was trying to do. Rather, I was creating constants that are used in many places in my code. The purpose is to simplify maintenance so that if I need to I can change the value of such a constant only once and not hunt for all of its uses throughout the code. As such, I believe that defining external constants is indeed a good practice.

Thanks again,

Abe
Aug 17 '07 #6
RRick
463 Expert 256MB
Your intentions are good, but you really are placing globals throuhghout your code which results in "code bloat". In this day and age of gigabyte memory, its not that severe, but it can be avoided.

If you want global consts, then what W4cats suggests is the one of the best ways to fix the bloat. Breaking code in header and source files works for subroutines and we don't mind that.

If you don't like the extern in your header file, then put your constants in a class as static const variables. Now you don't clutter up the namespace with Min and Max variable names. You still have to separate the declaration from the defintions, but hey, that's how static class variables work.
Aug 18 '07 #7

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

2 posts views Thread by Jochen Zeischka | last post: by
1 post views Thread by mead | last post: by
6 posts views Thread by Johannes Bauer | last post: by
6 posts views Thread by techBoy | last post: by
8 posts views Thread by ewpatton | last post: by
10 posts views Thread by zfareed | last post: by
6 posts views Thread by vsgdp | last post: by
9 posts views Thread by ramsatishv | last post: by
reply views Thread by rosydwin | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.