0

I'm working through the legacy C++ code that I'm trying to refresh. Contractor who previously worked on the code was very sloppy and didn't bother creating headers for some of the classes and would dump everything into .cpp, a lot of global variables, extremely large .cpp files of upward 7000 lines of code. Right now, I'm trying to separate the code into .h, .cpp files.

Existing code works (compiles and runs in production). I took part of the utility code and some variables and moved them to CASupporting.h. Compiled the project and got the following error in Visual Studio:

LNK1169 one or more multiply defined symbols found
Error   LNK2005 "int * CAValidation::__invReasonCounts" (?__invReasonCounts@CAValidation@@3PAHA) already defined in AddressValidatorLib.obj
Error   LNK2005 "int * CAValidation::__invReasonCounts" (?__invReasonCounts@CAValidation@@3PAHA) already defined in AddressValidatorLib.obj

Variable in questions is

//CASupporting.h
namespace CAValidation {
  ...
  int __invReasonCounts[7] = { 0 };
  ...
}

I did a global search to to find out if there are any other definitions of __invReasonCounts, but it came out empty. So, I suspect, it has to do with the way #include "CASupporting.h" is used. Currently the chain of includes looks like: CASupporting.h -> CAImpl.h -> CAImpl.cpp & CAValidator.h (2 files). CAValidator.h -> CAValidator.cpp

Out curiosity, I have moved out int __invReasonCounts[7] = { 0 }; from CASupporting.h right into namespace CAValidation in "CAImpl.cpp", where __invReasonCounts is being used. Project compiles without error.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
newprint
  • 6,936
  • 13
  • 67
  • 109
  • 2
    Unrelated: You may find the full text error messages on the Output Tab more useful, especially when trying to cut and paste, than the messages on the Error List. The Error List abbreviates the messages, sometimes leaving out that last bit of information you needed in order to take the correct action. – user4581301 Apr 11 '19 at 17:57
  • @user4581301, Wow. Thank you ! – newprint Apr 11 '19 at 18:08

1 Answers1

3

Yes, if you have a (non inline) global variable defined in the header, and the header is included into several .cpp files, you will have linker errors due to ODR violations.

A most common fix in legacy C++ is to move the definition into the .cpp file and leave the .h file with a declaration:

In .h:

extern int __invReasonCounts[7];

In .cpp:

int __invReasonCounts[7] = {0}; // compile-time initialization, safe

Also, keep in mind that symbols beginning with __ (two undescores) are reserved for implementation and not to be used in program code.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • 1
    Addendum explaining Sergey's last point in greater detail: [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – user4581301 Apr 11 '19 at 17:59