Board index » cppbuilder » char declaration in .h is considered re-declared wherever else it is used.

char declaration in .h is considered re-declared wherever else it is used.


2006-06-26 09:20:43 PM
cppbuilder46
Hello,
Problem #1:
whenever the following <short>include file is used <included>in 2 or more files, the linker
complains <warns>that the variable "wdays" is a "public symbol re-defined ...". So, if it's
included in source file A and also in source file B the linker says that it's defined in A and again
in B.
If I comment out the two "std::string" declarations, Mr. linker becomes happy again.
Is it apparent to anyone, viewing this header, why that might be so?
Problem #2:
Whenever I use one or both of the two "vector" typedefs the compiler complains that a "type" is
required ---- i.e. it doesn't see them in the header file. This must be a clue to the first problem,
surely.
I'm sure that I've done something stupid and blindingly obvious!!
Please help if you can.
Regards,
Rod.
//---------------------------------------------------------------------------
#ifndef uCommonDecsH
#define uCommonDecsH
#include <string>
#include <vector>
/*****************************************
FORWARD DECLARATION.
*****************************************/
class TLaneDetail;
//===============================================================/
const char *wdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "Unknown"};
const std::string sCRCRLF = "\r\r\n";
const std::string sCRLF = "\r\n";
enum enumFileStuff {MAX_INI_LINE=100, MAX_FILES=255, MAX_BUFFER=4096};
enum enumOpenClose {qryOpen, qryClose};
enum enumCountPeriod {cp_notset, cp_qtrHr, cp_hourly, cp_Daily};
enum enumvehicle_length {vl_none, vl_short, vl_medium, vl_long};
typedef std::vector<TLaneDetail*>TDVecLaneDetails;
typedef std::vector<std::string>TDVecFileNames;
//---------------------------------------------------------------------------
#endif
-- Rod
Please note that, due to time differences etc, it might be 24hrs before I
get back to this group so please consider yourselves thanked for any help
you may be able to provide.
 
 

Re:char declaration in .h is considered re-declared wherever else it is used.

On Mon, 26 Jun 2006 11:12:23 -0400, "Duane Hebert" < XXXX@XXXXX.COM >
wrote:
Quote

"Ed Mulroy" < XXXX@XXXXX.COM >wrote in message
news:449ff1f6$ XXXX@XXXXX.COM ...
>>...whenever the following <short>include file is used <included>
>>in 2 or more files, the linker complains <warns>that the variable
>>"wdays" is a "public symbol re-defined ..."....
>
>The linker is correct. Several items are allocated in each source file
>which includes the header file.

But why don't the header guards take care of this?
Hi Duane,
the header guard only affects multiple inclusion from _one_
compilation unit.
Here's what happens "en détail":
- Compiler works on file foo.cpp which #includes the header file in
question (once or several times - this doesn't matter). As part of
this process it defines a global variable 'wdays'.
- Compiler works on file bar.cpp which happens to #include the same
header file, and thus it defines another global variable 'wdays'.
(Remember: The compiler - by design - always knows only about one
source file at a time.)
Now the linker processes foo.obj and bar.obj and finds 2 instances of
'wdays' and complains.
Best regards
Helmut Giese
 

Re:char declaration in .h is considered re-declared wherever else it is used.

Quote
...whenever the following <short>include file is used <included>
in 2 or more files, the linker complains <warns>that the variable
"wdays" is a "public symbol re-defined ..."....
The linker is correct. Several items are allocated in each source file
which includes the header file.
Change this in the header file
---------------
const char *wdays[] =
{"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday","Saturday", "Unknown"};
const std::string sCRCRLF = "\r\r\n";
const std::string sCRLF = "\r\n";
---------------
To this:
---------------
extern const char *wdays[];
extern const std::string sCRCRLF;
extern const std::string sCRLF;
---------------
In one and only one source file that includes this header file, place this
some where in the file after the include of the header.
---------------
const char *wdays[] =
{"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday","Saturday", "Unknown"};
const std::string sCRCRLF = "\r\r\n";
const std::string sCRLF = "\r\n";
---------------
Quote
..Whenever I use one or both of the two "vector" typedefs the
compiler complains that a "type" is required ...
:
typedef std::vector<TLaneDetail*>TDVecLaneDetails;
typedef std::vector<std::string>TDVecFileNames;
I think that is most likely because of how the typedef'd names are used.
Please show the declarations and code about which the compiler complains.
. Ed
Quote
Rod wrote in message
news: XXXX@XXXXX.COM ...

Problem #1:
whenever the following <short>include file is used <included>
in 2 or more files, the linker complains <warns>that the variable
"wdays" is a "public symbol re-defined ...". So, if it's included in
source file A and also in source file B the linker says that it's
defined in A and again in B.

If I comment out the two "std::string" declarations, Mr. linker
becomes happy again.

Is it apparent to anyone, viewing this header, why that might be so?

Problem #2:
Whenever I use one or both of the two "vector" typedefs the
compiler complains that a "type" is required ---- i.e. it doesn't see
them in the header file. This must be a clue to the first problem,
surely.

//---------------------------------------------------------------------------
#ifndef uCommonDecsH
#define uCommonDecsH

#include <string>
#include <vector>

/*****************************************
FORWARD DECLARATION.
*****************************************/
class TLaneDetail;
//=============================================/

const char *wdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday",
"Saturday", "Unknown"};


const std::string sCRCRLF = "\r\r\n";
const std::string sCRLF = "\r\n";

enum enumFileStuff {MAX_INI_LINE=100,
MAX_FILES=255, MAX_BUFFER=4096};
enum enumOpenClose {qryOpen, qryClose};
enum enumCountPeriod {cp_notset, cp_qtrHr, cp_hourly, cp_Daily};
enum enumvehicle_length {vl_none, vl_short, vl_medium, vl_long};

typedef std::vector<TLaneDetail*>TDVecLaneDetails;
typedef std::vector<std::string>TDVecFileNames;

//---------------------------------------------------------------------------
#endif
 

{smallsort}

Re:char declaration in .h is considered re-declared wherever else it is used.

"Ed Mulroy" < XXXX@XXXXX.COM >wrote in message
Quote
>...whenever the following <short>include file is used <included>
>in 2 or more files, the linker complains <warns>that the variable
>"wdays" is a "public symbol re-defined ..."....

The linker is correct. Several items are allocated in each source file
which includes the header file.
But why don't the header guards take care of this?
Quote
Change this in the header file
<snip>
Making the std::string declarations static would
probably work here.
I've found that with BCB declaring const std::strings
in headers requires this.
It doesn't seem to complain about other
types. MSVC doesn't complain either.
Perhaps it's something with the std::basic_string<>template.
 

Re:char declaration in .h is considered re-declared wherever else it is used.

Duane Hebert wrote:
Quote
"Ed Mulroy" wrote in message
>>...whenever the following <short>include file is used <included>
>>in 2 or more files, the linker complains <warns>that the variable
>>"wdays" is a "public symbol re-defined ..."....
>
>The linker is correct. Several items are allocated in each source file
>which includes the header file.

But why don't the header guards take care of this?
They stop duplicats in a single module.
This problem is with several modules, each module gets a named copy.
Quote
Making the std::string declarations static would
probably work here.
It would stop the complaints, but would still duplicate the strings
per module.
 

Re:char declaration in .h is considered re-declared wherever else it is used.

"Helmut Giese" < XXXX@XXXXX.COM >wrote in message
Quote
Now the linker processes foo.obj and bar.obj and finds 2 instances of
'wdays' and complains.
But should it complain if they're both defined the same?
And why does it not complain for types like int?
For example, I have a header file for my main const defs.
It's included all over the place. With BCB I had to make
the std::strings static but ints, doubles etc don't have a
problem. In our MS builds we don't need to do that
but since we use the same code in both, the static
ones don't hurt anything.
While Ed's solution is correct, it forces a definition in
one and only one cpp file. In our case, we have several
projects using these consts. There's no common modules
that are guaranteed to always be there so we'd end up
defining them in main. That's why I suggested making
the strings static.
 

Re:char declaration in .h is considered re-declared wherever else it is used.

Duane Hebert wrote:
Quote
While Ed's solution is correct, it forces a definition in
one and only one cpp file. In our case, we have several
projects using these consts. There's no common modules
that are guaranteed to always be there so we'd end up
defining them in main. That's why I suggested making
the strings static.
I think the proper solution would be to list them in the header, and
define then in a cpp of the same name. The cpp then gets compiled and
placed in a library that all projects can read.
 

Re:char declaration in .h is considered re-declared wherever else it is used.

"Duane Hebert" < XXXX@XXXXX.COM >wrote:
Quote
"Helmut Giese" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>Now the linker processes foo.obj and bar.obj and finds 2 instances of
>'wdays' and complains.

But should it complain if they're both defined the same?
And why does it not complain for types like int?
That's the 'One Definition Rule'. It mean you may not define (as opposed
to declare) the same thing in more than one 'translation unit' (that's a
source file, to you and me).
The exceptions are (IIRC):
inline functions
template functions
const integer types
something within an anonymous namespace
something explicitly 'static'
(Others may come up with others.)
The ODR really is interested in definitions that differ, but
historically, the easiest way to avoid differing definitions is to limit
the allowed number to 1.
Quote
For example, I have a header file for my main const defs.
It's included all over the place. With BCB I had to make
the std::strings static but ints, doubles etc don't have a
problem. In our MS builds we don't need to do that
but since we use the same code in both, the static
ones don't hurt anything.
MS is *cough* differently buggy.
Quote
While Ed's solution is correct, it forces a definition in
one and only one cpp file. In our case, we have several
projects using these consts. There's no common modules
that are guaranteed to always be there so we'd end up
defining them in main. That's why I suggested making
the strings static.
Which works, but relies on the linker coalescing constant strings that
it discovers to be the same.
Alan Bellingham
--
Me <url:mailto: XXXX@XXXXX.COM ><url:www.doughnut.demon.co.uk/>
ACCU - C, C++ and Java programming <url:accu.org/>
The 2006 Discworld Convention <url:www.dwcon.org/>
 

Re:char declaration in .h is considered re-declared wherever else it is used.

"Duane Hebert" < XXXX@XXXXX.COM >writes:
Quote
"Helmut Giese" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>Now the linker processes foo.obj and bar.obj and finds 2 instances of
>'wdays' and complains.

But should it complain if they're both defined the same?
And why does it not complain for types like int?
Violations of the "one definition rule" result in undefined behavior,
and are not required to be reported by the compiler.
However, if you declare a type at file scope to be "const" it will
have internal linkage and be "local" to the file that includes it.
(Just like making them "static" does.)
Quote
For example, I have a header file for my main const defs.
It's included all over the place. With BCB I had to make
the std::strings static but ints, doubles etc don't have a
problem. In our MS builds we don't need to do that
but since we use the same code in both, the static
ones don't hurt anything.
Static data declared in a header can be problematic. Every source
file that includes that header will have a seperate instance of that
variable. For example, if you have two files that include your
header, say, a.cpp and b.cpp, and you print out the variable's address
from each file, they will each have a different address. Another way
to interpret that is that you have multiple instances of the
variable... a waste of space and possibly slowing down your program
startup time if constructors are involved.
Quote
While Ed's solution is correct, it forces a definition in
one and only one cpp file. In our case, we have several
projects using these consts. There's no common modules
that are guaranteed to always be there so we'd end up
defining them in main. That's why I suggested making
the strings static.
You can create a library to which all of your projects are linked that
contains the definitions.
Alternately, if you declare them to be const, then they have
--
Chris (TeamB);
 

Re:char declaration in .h is considered re-declared wherever else it is used.

Chris Uzdavinis (TeamB) < XXXX@XXXXX.COM >writes:
Quote
However, if you declare a type at file scope to be "const" it will
have internal linkage and be "local" to the file that includes it.
(Just like making them "static" does.)
Also, by "file" I mean translation unit. Or "Thingie being compiled
with this particular invocation of the compiler."
Quote
Static data declared in a header can be problematic. Every source
file that includes that header will have a seperate instance of that
variable.
Also, the compiler may be smart enough to realize that data objects
with internal linkage will not be used anywhere else, and the
optimizer may "inline" the access to the values. Since they do not
change this is ok. (In that case, it may not actually create a global
instance even if logically it could.) If you take its address, then
that forces a global instance to be created, of course, because the
address must be valid. However, all other uses of that value may
still be "inlined."
--
Chris (TeamB);
 

Re:char declaration in .h is considered re-declared wherever else it is used.

Quote
...While Ed's solution is correct, it forces a definition in one and only
one cpp file...
Just as it should.
Quote
In our case, we have several projects using these consts. There's no
common modules ...
I don't think so.
What you describe is several projects, each of which uses its own constants
with names identical to those used in other projects. As there are no
common modules there are no conflicts.
Quote
.. That's why I suggested making the strings static...
The keyword 'const' is in effect static by default as the name is not added
to the public symbols list unless a declaration also declares it as
'extern'. In the Rod's case he has several source files using the
constants. Declaring them as static would cause each of those source files
to create duplicate arrays, a waste of space.
Quote
But should it complain if they're both defined the same?
And why does it not complain for types like int? ...
:
...With BCB I had to make the std::strings static but ints, doubles etc
don't have a problem...
Because the string is a class with constuctor to which the initialization
char* string is given and which both requires some allocated memory and a
constructor call. The int, double, etc are handled in a manner analagous to
a #define so require no memory allocation for the const.
A declaration of two class instances with the same initialization does not
guarantee or even imply that the internal states of the two instances will
match at the main or WinMain point when the program logically starts. The
two class instances may be logically 'const' at the point the programmer
begins to deal with them but each has been configured by the actions of its
constructor.
. Ed
Quote
Duane Hebert wrote in message
news:44a005e5$ XXXX@XXXXX.COM ...

"Helmut Giese" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>Now the linker processes foo.obj and bar.obj and finds 2 instances of
>'wdays' and complains.

But should it complain if they're both defined the same?
And why does it not complain for types like int?

For example, I have a header file for my main const defs.
It's included all over the place. With BCB I had to make
the std::strings static but ints, doubles etc don't have a
problem. In our MS builds we don't need to do that
but since we use the same code in both, the static
ones don't hurt anything.

While Ed's solution is correct, it forces a definition in
one and only one cpp file. In our case, we have several
projects using these consts. There's no common modules
that are guaranteed to always be there so we'd end up
defining them in main. That's why I suggested making
the strings static.
 

Re:char declaration in .h is considered re-declared wherever else it is used.

To show it better:
class KeepARandValue
{
public:
KeepARandValue(int offset)
: rand_value(std::rand() + offset)
{}
int Value() const { return rand_value; }
private:
int rand_value;
};
How can the linker combine multiple instances of these, one from each source
file? They have DIFFERENT internal data. Class instances cannot be
combined, even if declared 'const'.
. Ed
 

Re:char declaration in .h is considered re-declared wherever else it is used.

"Alan Bellingham" < XXXX@XXXXX.COM >wrote in message
Quote
That's the 'One Definition Rule'. It mean you may not define (as opposed
to declare) the same thing in more than one 'translation unit' (that's a
source file, to you and me).

The exceptions are (IIRC):

inline functions
template functions
const integer types
something within an anonymous namespace
something explicitly 'static'
Ok. This likely explains what I'm seeing.
Quote
>For example, I have a header file for my main const defs.
>It's included all over the place. With BCB I had to make
>the std::strings static but ints, doubles etc don't have a
>problem. In our MS builds we don't need to do that
>but since we use the same code in both, the static
>ones don't hurt anything.

MS is *cough* differently buggy.
Maybe. But the thing that I don't see is that
in both MS and BCB builds, my header has
lines like:
const double MaxDouble(std::numeric_limits<double>::max());
Neither complains about this. Is it because it's inlined?
 

Re:char declaration in .h is considered re-declared wherever else it is used.

"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
You can create a library to which all of your projects are linked that
contains the definitions.

Alternately, if you declare them to be const, then they have
What about wrapping them in an anonymous namespace?
 

Re:char declaration in .h is considered re-declared wherever else it is used.

"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
Duane Hebert wrote:

>While Ed's solution is correct, it forces a definition in
>one and only one cpp file. In our case, we have several
>projects using these consts. There's no common modules
>that are guaranteed to always be there so we'd end up
>defining them in main. That's why I suggested making
>the strings static.

I think the proper solution would be to list them in the header, and
define then in a cpp of the same name. The cpp then gets compiled and
placed in a library that all projects can read.
Thanks. That would work.