4

I am refactoring a c++ code and there is something I cannot understand. The code is declaring a set of arrays in a header file then include that header file in source files when needed. All arrays are "const unsigned char[]" except one which is "const char *[]" array. The latter is surrounded with an #ifdef SOMETHING. If SOMETHING is not defined code is built successfully, otherwise I got linker errors of multiple definitions for this "char *[]" only.

As a fix, I can eliminate those linker errors by adding "static" to "const char* XX[3] = {"X", "Y", "Z"}". This will keep the definition specific to the translation unit.

However, what I cannot understand why "multiple definitions" errors only occur with "const char* []" array and not with the others "const unsigned char[]" despite they are not preceded by a "static" keyword? Could someone explain that to me please?

3
  • Don't define the arrays in the header files, only declare them. For example, const char* XX[3] = {"X", "Y", "Z"}; is a definition. Commented Jan 13, 2015 at 9:48
  • Yes Joachim, I know it is better to do as you said, but my question here is different it is about linker errors why gotten only for char*[] and not for unsigned char[] Commented Jan 13, 2015 at 9:49
  • 1
    The crucial difference lies in the const, not the * or the unsigned. const unsigned char[] is a const array, const char*[] is a non-const array (of const pointers). Commented Jan 13, 2015 at 10:04

1 Answer 1

8

Constant variables at namespace scope implicitly have internal linkage (if you will, they are implicitly static). The following declares and defines two distinct objects.

// A.cpp               // B.cpp

const T foo = 1;       const T foo = 2;

If you wanted external linkage, you'd have to say extern const T foo;.

By contrast, non-constant variables at namespace scope have external linkage (if you will, they're implicitly declared extern) and all denote the same object, so you are violating the one-definition rule:

// A.cpp               // B.cpp

U bar = 1;             U bar = 2;      // ODR violation

Here, if you wanted internal linkage, you'd have to say static U bar;.

This is your case. You have T = char [] and U = const char * []. (Here const T produces the type const char [] by 8.3.4/1.)


The solution is to not define your variables in headers if the variables have external linkage, since the header gets included in multiple translation units. Instead, only declare the variable in the header and define it in one single translation unit:

library.h:

extern U bar;            // in your case, extern const char * XX[];

library_impl.cpp:

#include "library.h"

U bar = 3;
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you for your answer. But, why you consider "const char* []" as "non-constant" at namespace. I still cannot understand this point. Could you clarify it please.
@Aymen: Because it is non-constant. What makes you think it's constant? (Hint: Please make sure you understand the C++ type declaration syntax.)
@Aymen: "At namespace scope" is C++'s way of saying "global variable". It's just that "global" isn't quite precise, because C++ has namespaces, but it's essentially that.
@Aymen: You can't just take random stuff out of context. Your type is U = V *, which is not the same as const U = V * const. The fact that V = const char is irrelevant. You have a pointer, and the pointer is mutable. It's true that the pointer points to something immutable, but that's irrelevant for the pointer itself. You're confusing const char * with char * const.
Thank you. You are too fast :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.