1

Suppose I have the following two files:

test.cpp

inline double pi { 3.1415 };
#include <iostream>

void test() {

    std::cout << pi << std::endl;

}

and

main.cpp

inline double pi { 2.178 };

void test();

#include <iostream>

int main() {

    std::cout << pi << std::endl;
    test();

}

inline variables by default have external linkage. So, my initial thought, according to the One Definition Rule (ODR) is that the same variable can be declared across multiple translation units as long as the variable is declared inline and contains the same exact definition

So my first question is, why does this program compile if, even though the variables are declared inline, they have different definitions across the translation units?

Second, what is the difference between an inline non-const and an inline const variable?

For example, if you run the code above you should get the following output

2.178
2.178

However, if you go to both files and make pi a const double, that is inline const double pi {3.1415} and inline const double pi {2.178}

You get the following output:

2.178
3.1415

What exactly is happening here?

Mutating Algorithm
  • 2,604
  • 2
  • 29
  • 66
  • You are violating ODR if those definitions are different. That's UB. – cigien Apr 10 '20 at 01:36
  • What do you think happens when you put an inline variable in a header? The linker won't check if _every_ definition is identical; it will just pick one and run with it. As for your second question, if a variable is constant and you never attempt to take its address, the compiler can safely inline it regardless of whether or not it has external linkage. – Brian61354270 Apr 10 '20 at 01:37
  • @cigien The compiler does not complain, which is why i'm confused. – Mutating Algorithm Apr 10 '20 at 01:38
  • @MutatingAlgorithm There's nothing to complain about. Each TU is fine. At most the linker could diagnose it. – cigien Apr 10 '20 at 01:39
  • The behavior you're exhibiting here is discussed at length in [this answer](https://stackoverflow.com/a/45710235/11082165) to a related question. – Brian61354270 Apr 10 '20 at 01:43
  • 1
    One question per question please. – Asteroids With Wings Apr 10 '20 at 01:43

1 Answers1

2

Your program has undefined behaviour, for exactly the reason you give.

Your toolchain is not required to diagnose undefined behaviour and, in cases that are hard to "spot" in general, which is many of them, it won't even bother. At best, the linker (not the compiler) could spot this particular case during build, if the people who wrote it had deemed this to be useful enough to warrant the extra work and build time.

But, no: this rule falls into the category of being the programmer's responsibility. You broke the rules, and now your program is broken, in complex ways that we could probably work out with enough information about your computer, toolchain, moon-phase, mood, shoe colour and program's assembly… but this would not really be of any value.

Adding const may lead to the compiler (not the linker) eliding "references" to this variable in some places, literally "inlining" the initialiser value at the point of use, as an optimisation. It can do that when it knows the value won't have changed from initialisation (thanks to the const). The result is that you're no longer observing so much weirdness from your undefined behaviour, because the behaviour you see from your program is more constrained to the individual translation units.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35