now I have 2 c++ source files: test9.cpp test10.cpp, they both have a inline function with the same name.
test9.cpp:
1 #include <iostream>
2 using namespace std;
3 void test();
4 inline void f1()
5 {
6 cout << "inline f1 in test9.cpp" << endl;
7 }
8 int main()
9 {
10 f1();
11 test();
12 return 0;
13 }
test10.cpp:
1 #include <iostream>
2 using namespace std;
3 inline void f1()
4 {
5 cout << "inline f1 in test10.cpp" << endl;
6 }
7 void test()
8 {
9 f1();
10 }
now compile them with g++: g++ test9.cpp test10.cpp ./a.out I get the following result:
inline f1 in test9.cpp
inline f1 in test9.cpp
what's wrong? I thought it would be: "inline f1 in test9.cpp inline f1 in test10.cpp"
who can tell me why? how does the g++ compiler treats the inline function?
While the compiler will allow you (nay, require you!) to redefine functions marked inline, the default of external linkage still applies, so you are breaking the One Definition Rule. This results in undefined behaviour and the outcome that you are seeing.
[C++11: 7.1.2/4]: An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [..]
Related
This question already has answers here:
C++ Multiple Definition of Struct
(2 answers)
Why is there no multiple definition error when you define a class in a header file?
(3 answers)
Closed 1 year ago.
C++ translator seems uses correct declared structs of the same name, but then linker mismatches them without any warning or error! And this also leads to UB, because at least inappropriate ctor/dtor are used for the memory region.
Here is minimal sandbox code. Each struct Test should be treated as some internal non-public structure used only in one own .cpp file.
file1.cpp
#include <iostream>
using namespace std;
void someFunc();
struct Test
{
Test() { std::cout << "1 "; }
~Test() { std::cout << "~1" << std::endl; }
};
int main()
{
{
Test test;
}
someFunc();
return 0;
}
file2.cpp
#include <iostream>
struct Test {
Test() { std::cout << "2 "; }
~Test() { std::cout << "~2" << std::endl; }
};
void someFunc() {
Test test;
}
(Downloadable and buildable CMake-project just in case: https://file.io/dzafv409B2t0)
Output will be:
1 ~1
1 ~1
So, I expected:
Successful build with output: 1 ~1 2 ~2
Or failed build with multiple definition error
Yes, I can resolve the problem if:
Rename the struct
Put the struct into anonymous namespace - force internal linkage
...but this doesn't answer the main question:
Why linker behaves so? Why does it silently links to first available matching symbol (among several) instead of reporting multiple definition error?
Update: As I understood, this mechanism allows to include header with class declaration (with inline code) into several different source files without multiple definition problem.
Consider the template function g() and free function f():
#include <iostream>
#include <source_location>
auto g(auto...) {
std::cout << std::source_location::current().column() << "\n";
}
auto f() {
std::cout << std::source_location::current().column() << "\n";
}
int main() {
g();
f();
}
Compiled with GCC-trunk get following output:
43
44
Why g() and f() yield different results? I expect the results are the same. Why a unit offset disappeared during the instantiation of the template?
I file a PR 99672 to GCC Bugzilla. Jakub Jelinek (one of the GCC contributor) reply me:
I think the standard doesn't specify anything about what exactly the
column should be, so using different columns isn't standard violation.
but he still did a patch to fix it.
I would like to ask a question about the output when I called an inline function, that was declared inside MyHeader.h, which was defined in both source_1.cpp and source_2.cpp files, using the int main() function inside source_2.cppfile.
When I do such a call, the one defined inside the source_1.cpp function is called. The codes are like;
My MyHeader.h contains the following line of codes:
#pragma once
#include <iostream>
inline int func(void);
My source_1.cpp contains the following line of codes:
#include "MyHeader.h"
int func(void)
{
std::cout << "func(), inside source_1, was called. 102 * 102 will be returned." << "\n";
return 102 * 102;
}
void source_1(void)
{
std::cout << "source_1() was called. func() will be called." << "\n";
func();
}
My source_2.cpp contains the following line of codes:
#include "MyHeader.h"
int func(void)
{
std::cout << "func(), inside source_2, was called. 102 * 102 will be returned." << "\n";
return 102 * 102;
}
void source_2(void)
{
std::cout << "source_2() was called. func() will be called." << "\n";
func();
}
int main()
{
std::cout << "main() was called." << "\n";
source_2();
}
This is the output:
main() was called.
source_2() was called. func() will be called.
func(), inside source_1, was called. 102*102 will be returned.
I wish to know the reason.
You violated the one definition rule. You are not permitted to have non-static objects in your program with different implementations. The compiler/linker is free to choose any implementation it finds, which can lead to very hard to find bugs.
Your source_2 function called func function of source_1.cpp because func is declared as inline , not static . When the linker gets a inline function, it remove all copies of that function except one. So the func function of source_1.cpp is kept, other one is removed by the linker. If you want to have two separate implementation of one function in two source file, declare the function as static . This prevents the linker from removing multiple functions of same name.
This question already has answers here:
How to define a const double inside a class's header file?
(3 answers)
Closed 7 years ago.
Something.h
1 class Something
2 {
3 private:
4 static int s_nIDGenerator;
5 int m_nID;
6 static const double fudgeFactor; // declaration - initializing here will be warning
7 public:
8 Something() { m_nID = s_nIDGenerator++; }
9
10 int GetID() const { return m_nID; }
11 };
foo.cpp
1 #include <iostream>
2 #include "Something.h"
3
4 // This works!
5 //const double Something::fudgeFactor = 1.57;
6
7 int main()
8 {
9 Something cFirst;
10 Something cSecond;
11 Something cThird;
12
13 const double Something::fudgeFactor = 3.14;
14
15 using namespace std;
16 cout << cFirst.GetID() << endl;
17 cout << cSecond.GetID() << endl;
18 cout << cThird.GetID() << endl;
19 return 0;
20 }
When trying to define the value of the static member variable of Class Something inside main, I encounter a compiler error as given below. Assigning a value outside the main() works fine. I understand that static member variables can be given a value only once, but why does assigning it outside a function versus inside a function matter?
$ clang++ foo.cpp
foo.cpp:13:29: error: definition or redeclaration of 'fudgeFactor' not allowed
inside a function
const double Something::fudgeFactor = 3.14;
~~~~~~~~~~~^
1 error generated.
You are not assigning the variable inside the function; you are defining it (and initializing it). You can't do that inside the function because of scope rules. The variable is declared in the global (namespace) scope; therefore it also has to be defined in the namespace scope. It is not a local variable.
By the way, for static const variables, recent C++ standards allow you to initialize them at the point of declaration (as in your .h file) but you still have to define them, but this time without the initializer:
const double Something::fudgeFactor;
Static data members of a class needs to have external linkage. By this rule, the static members must be defined in namespace scope.
Consider following source files
1.cpp
#include <iostream>
using namespace std;
struct X
{
X()
{
cout << "1" << endl;
}
};
void bar();
void foo()
{
X x;
}
int main()
{
foo();
bar();
return 0;
}
2.cpp
#include <cstdio>
struct X
{
X()
{
printf("2\n");
}
};
void bar()
{
X x;
}
Is program compiled from these files well-formed? What should be in it's output?
I've expected linker error due to violation of One Definition Rule or output "1 2". However it prints out "1 1" when compiled with g++ 3.4 and VC 8.0.
How this can be explained?
This does violate ODR (3.2) - specifically that you can have more than one definition of an inline function, but those definitions must be identical (3.2/5) - and leads to undefined behavior, so anything may happen and the compiler/linker is not required to diagnose that. The most likely reason why you see that behavior is that function calls are inlined and do not participate in linking, so no link error is emitted.
It is undefined behaviour (with no required diagnostic) if inlined functions (such as your class constructor) have different definitions in different translation units.