4

I compile those files as single program with Visual studio 2019 in win10

My project have just two source files:

/**** a.cpp ****/

namespace pers{
    const int LEN = 5;
}

/**** b.cpp ****/

namespace pers {
    const int LEN = 5;
}

int main() {
    return 0;
}

It can be compiled successfully.But I dont konw why? I defined LEN twice!!

so, I delete the const :

/**** a.cpp ****/

namespace pers{
    int LEN = 5;
}

/**** b.cpp ****/

namespace pers {
    int LEN = 5;
}

int main() {
    return 0;
}

Now it doesn't work! So, my question is what happend? const variable in diffierent source files can be defined twice or more (means NO multi-definition error) .

Meanwhile, compiler will throw "multi-definition error" if do this:

namespace pers {
    const int LEN = 5;
    const int LEN = 5; // multi-definition error

    const int LEN2 = 10;
}
namespace pers {
    const int LEN2 = 10; // multi-definition error
}


int main() {
    const int a = 10;
    const int a = 10; // multi-definition error

    return 0;
}
Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
achange
  • 61
  • 3
  • 3
    whats your question? How do you compile the two? – 463035818_is_not_an_ai May 24 '22 at 14:31
  • Does this answer your question? [extern const in c++](https://stackoverflow.com/questions/9661146/extern-const-in-c) – Mgetz May 24 '22 at 14:31
  • You are violating the one definition rule. – drescherjm May 24 '22 at 14:33
  • 4
    Those should compile. They won't link, because there are two separate strong linkage **definitions** with the same name. – Eljay May 24 '22 at 14:33
  • in my opinion this should work, const it doesn't means in this situation – Eriss69 May 24 '22 at 14:56
  • 1
    @Eriss69 -- `const` does matter. Unfortunately, this question got closed while I was writing an answer explaining the difference. – Pete Becker May 24 '22 at 15:27
  • @Eljay -- the C++ standard doesn't talk about "strong linkage definitions". The first pair is okay because both definitions are `static`; the second pair is not okay because they aren't. – Pete Becker May 24 '22 at 15:31
  • @PeteBecker • the second snippet claimed "it can't be compiled". But the OP neglected to mention how it was compiled, on what platform, and with which compiler. The implementation details aside as to the specific "it can't be compiled" encountered; I concur, you are correct. That is the upstream problem that the linker (assumably) is running afoul of. – Eljay May 24 '22 at 16:18
  • @Eljay -- it doesn't matter what platform or what compiler; the second example is not valid C++. A compiler that accepts it does not conform to the language definition. – Pete Becker May 24 '22 at 18:06
  • @PeteBecker • The second example is valid C++, as long as those two CPP files are part of different programs. – Eljay May 24 '22 at 18:25
  • @Eljay -- that is, indeed, true. Do you **really** think that's what was intended? – Pete Becker May 24 '22 at 18:26
  • @PeteBecker • Without knowing how it was compiled, on what platform, with which compiler, and the intent of the OP, I don't know. We have a dearth of information, and the OP doesn't seem to be interested in their question. Maybe the OP is making new programs, but compiling all the source together, `g++ *.cpp` (which has been an issue some new programmers have asked on SO before). – Eljay May 24 '22 at 18:56
  • 2
    @Eljay -- seriously? Do you worry that the fact that I use the name `LEN` as a global in my code might invalidate your use of the name `LEN` as a global in your code? Do you think that **anybody** does? – Pete Becker May 24 '22 at 19:23
  • @PeteBecker • Thank you for the warning, I'll avoid using `LEN` in my code so our code doesn't collide. – Eljay May 24 '22 at 20:13
  • Thanks for Eljay and Pete Becker and all ! I have added some descriptions for my code. I am new hand for c++. those code worte when I read 《C++ primer plus》5th, so, they are not for any PROJECT (such as win12), just for learning :) Thank all again. I have more confidence to learn C++ well ! – achange May 25 '22 at 02:42
  • the same question's address:https://stackoverflow.com/questions/72371532/why-no-multi-definition-error-in-diffierent-file-if-define-const-variable-repeat – achange May 25 '22 at 03:04

1 Answers1

8

Let's see on case by case basis what is happening:

Case 1

Here we consider:

a.cpp

namespace pers{
    const int LEN = 5; //this LEN has internal linkage and is different from the LEN defined in b.cpp
}

b.cpp

namespace pers {
    const int LEN = 5; //this LEN has internal linkage and is different from the LEN defined in a.cpp
}

int main() {
    return 0;
}

It can be compiled successfully.But I dont know why?

This is because LEN has internal linkage meaning its use is limited to a single translation unit and so the LEN in a.cpp and b.cpp are not the same. This can be see from basic.link which states:

A name having namespace scope has internal linkage if it is the name of

  • a non-inline variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or

And also,

When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.

(emphasis mine)

This means the LEN In a.cpp and the LEN in b.cpp are distinct from each other and so there is no multiple definition error.


I defined LEN twice!!

As explained above, you're not defining the same LEN twice. They are different from each other because they have a namespace scope and are const qualified.

Case 2

Here we consider:

a.cpp

namespace pers{
    int LEN = 5; //this LEN has external linkage and is the same a the LEN in b.cpp
}

b.cpp

namespace pers {
    int LEN = 5; //this LEN has external linkage and is the same LEN as in a.cpp
}

int main() {
    return 0;
}

In this case, LEN has external linkage meaning both the LEN in a.cpp and b.cpp are the same and since you're defining the same name twice, you're violating ODR.

Case 3

Here we consider:

namespace pers {
    const int LEN = 5; //OK, define `LEN` with internal linkage for the first time 
    const int LEN = 5; // error because you're defining the same LEN with internal linkage for the second time in the same TU

    const int LEN2 = 10;
}



int main() {
    const int a = 10;  //define a for the first time in this TU
    const int a = 10; // error because you're defining the same a for the second time in the same TU

    return 0;
}

In this case 3, you're definining the same LEN twice and hence getting the mentioned error. We cannot define any entity more than once in the same translation unit.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • thanks. I read the "basic.link" content, and know that `const` means `static` implicitly. I have learned this rule, but forget it, maybe namespace confuse me. Thanks again. – achange May 25 '22 at 07:25
  • @achange Yes, `const` in your example means implicitly static. See [this](https://stackoverflow.com/a/70523572/12002570) where i explained the same. You're welcome. – Jason May 25 '22 at 07:29
  • See also here about internal linkage https://en.cppreference.com/w/cpp/language/storage_duration it also lists the exception *non-volatile non-template non-inline non-exported const-qualified variables (including constexpr) [at namespace scope] that aren't declared extern and aren't previously declared to have external linkage [have internal linkage]* – Sebastian May 25 '22 at 07:30
  • @achange I think, for linking step it's enough to think of namespaces as of an addition to the names of symbols. Oh, to add to that,, try remove the name of namespace and see how that works. – Swift - Friday Pie May 26 '22 at 06:49