Duplicate character error associated with const char * [] declaration

I would really like to help diagnose the source of the duplicated character error that I get when I try to compile with g ++ 4.2.1.

Specific error

ld: duplicate symbol _SOCIODEM_FILENAMES in /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//ccP3yVgF.o and /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//cc1NqtRL.o collect2: ld returned 1 exit status 

The error only occurs when I include this declaration in a file called Parameters.h :

 // Parameters.h #ifndef PARAMETERS_H #define PARAMETERS_H // ...[code snipped]... const int NUM_SOCIODEM_FILES = 5; const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt", "FLEDGE_PDF.txt", "PAIR_PDF.txt", "BIRTH_AGE_PDF.txt", "SPLIT_PDF.txt" }; // ...[code snipped]... #endif 

I searched all my files and this is the only place where SOCIODEM_FILENAMES declared. When I comment on an ad, the duplicate character error disappears.

I am not familiar with linker errors (if so), and I would like to help fix the problem. All of my header files have #ifndef...#define...#endif wrappers. My compilation team

 g++ -o a.out -I /Applications/boost_1_42_0/ Host.cpp Simulation.cpp main.cpp Rdraws.cpp 

Thanks in advance.


Solution Summary

Now I have in Parameters.h:

 const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt", "FLEDGE_PDF.txt", "PAIR_PDF.txt", "BIRTH_AGE_PDF.txt", "SPLIT_PDF.txt" }; 

All other definitions and declarations in Parameters.h are not changed. Andrey and other commentators summarize an alternative approach using extern , which is superfluous for my purposes.

+7
c ++ linker
source share
5 answers

For some reason, none of the answers so far has helped explain the difference between the whole NUM_SOCIODEM_FILES object and the SOCIODEM_FILENAMES array SOCIODEM_FILENAMES . The latter causes a linker error for reasons already explained: because you include the header file in several implementation files. However, the former would join without any problems (because there really are no problems with declaring NUM_SOCIODEM_FILES ). Why?

The reason for this is because your NUM_SOCIODEM_FILES object NUM_SOCIODEM_FILES declared const . In C ++, const objects have an internal link by default, which means that they do not cause binding problems, even if they are defined in multiple implementation files. In other words, in C ++ your NUM_SOCIODEM_FILES equivalent

 static const int NUM_SOCIODEM_FILES = 5; /* internal linkage */ 

therefore, it does not lead to any binding problems.

At the same time, your SOCIODEM_FILENAMES not declared a constant, so by default it gets an external connection and ultimately leads to linker errors. But if you declare your SOCIODEM_FILENAMES as const , the problem will disappear.

 const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { ... 

Notice where the extra const added in the declaration. If you just add this extra const and leave everything else as it is (i.e., save the definition if SOCIODEM_FILENAMES in the header file), the linker will not report an error even if you include the header file in several translation units.

This is not recommended because this way you will pass your internal SOCIODEM_FILENAMES link and get a separate copy of the SOCIODEM_FILENAMES array in each translation unit - something that might work fine, but still makes very little sense. So, for your array it is usually better to use the extern approach recommended in other answers.

However, note that you should not usually do this for the declaration NUM_SOCIODEM_FILES !!! This is normal as indicated in the header file. If you are not trying to do something unusual, scalar constants usually need to be defined with an initializer in the header files - thus, they can be considered as compile-time constants in all translation units, which is quite valuable. Therefore, beware of the strange tips present in some other answers to move the definition of NUM_SOCIODEM_FILES to a .cpp file - this actually does not make sense and is absolutely wrong.

+14
source share

Most likely, you #include use this file in several source files. The problem is that each inclusion leads to a separate definition for a variable named SOCIODEM_FILENAMES . Turning on the guards will not help. Include protective measures to prevent multiple declarations within the same compilation unit; they do not prevent multiple definitions in multiple compilation units.

What you need to do is declare these variables as extern in the header, and then define them in a single file. eg.

 // Parameters.h #ifndef PARAMETERS_H #define PARAMETERS_H // ...[code snipped]... extern const int NUM_SOCIODEM_FILES; extern const char * SOCIODEM_FILENAMES[]; // ...[code snipped]... #endif 

and then:

 // Parameters.cpp (or some other source file) const int NUM_SOCIODEM_FILES = 5; const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt", "FLEDGE_PDF.txt", "PAIR_PDF.txt", "BIRTH_AGE_PDF.txt", "SPLIT_PDF.txt" }; 

You can get away from this not for int , because it is a constant integer, so the compiler can simply treat it as a compile-time constant, and it will never be displayed in compiled code. However, char* cannot be handled this way and therefore must have exactly one definition (known as "one definition rule" in C ++).

+7
source share

The header protector ( #ifndef..#endif wrapper) simply prevents you from including the same header several times in the same source file. You can still have several source files containing this header, and each of them will declare this symbol separately. Since they all have the same name, combining these sources together will result in a clash of symbol names. You probably want to declare a character in the source file instead of the header file

+2
source share

The problem is that you put the definition in the header file. If you include this file in several compilations (a .cpp file), you will create several definitions, and at the time of the link you will get this error.

You need to put both of these definitions in a .cpp file and place only the declaration in the header file:

 extern const int NUM_SOCIODEM_FILES; extern const char * SOCIODEM_FILENAMES[]; 
+2
source share

Like others, one way to do this is to declare NUM_SOCIODEM_FILES and SOCIODEM_FILENAMES as extern and define them once in the external file. Another way is to declare them as static - this causes them to be duplicated in each object file, which includes a header, but will not create an error, since the definition is private to this object file. Which option you choose depends entirely on your own preferences.

+2
source share

All Articles