I have a large project (20+ files) but I managed to set up this small example which recreates my problem. Essentially I have one file (A.cpp) including a second file (B.cpp), but that second file needs several of the variables and functions from the first file. Observe:
A.h:
#ifndef _A_H_
#define _A_H_
static void foo(int _something);
#endif // #ifndef _A_H_
A.cpp:
#include <iostream>
#include "A.h"
#include "B.h"
using namespace std;
static void foo(int _something)
{
cout << _something << "\n";
}
int main(int argc, char *argv[])
{
B *b;
foo ( 123 ); // So we don't get that pesky defined-not-used warning
b = new B ();
b->display ( 123 );
}
B.h:
#ifndef _B_H_
#define _B_H_
#include "A.h"
class B
{
public:
B();
~B();
void display ( int x );
};
#endif // #ifndef _B_H_
B.cpp:
#include "B.h"
void B::display ( int x )
{
foo ( x );
}
And I am compiling it like so, g++ -Wall A.cpp B.cpp -o main but then I get this error:
A.h:3:13: warning: ‘void foo(int)’ used but never defined [enabled by default]
/tmp/ccFwfZa6.o: In function `main':
A.cpp:(.text+0x54): undefined reference to `B::B()'
/tmp/ccM8SNBK.o: In function `B::display(int)':
B.cpp:(.text+0xd): undefined reference to `foo(int)'
collect2: ld returned 1 exit status
I can tell it's a link error, but I can't tell why I am getting that error.
EDIT:
In my original code I am still getting an error, this time it's about the multiple definition of an integer, here is the error I am getting:
B.o:(.bss+0x4): multiple definition of `some_var'
A.o:(.bss+0x4034): first defined here
collect2: error: ld returned 1 exit status
make: *** [main] Error 1
and I am creating the variable some_var like so
A.h:
#ifndef _A_H_
#define _A_H_
static void foo(int _something);
int some_var;
#endif // #ifndef _A_H_
How is it possible that some_var would get defined more than once when I have those conditional guards?
You have no B::B() body at all. Add one, and don't forget about destructor.
Also, remove static from foo().
The problem now is that each source file that #includes a.h gets a definition of int some_var;. In general, variables should be declared in headers and defined in one source file. So in your header you need
extern int some_var;
and in one source file (presumably a.cpp)
int some_var;
Thanks to Pete Becker I figured out the problem, and it stemmed mostly from a lack of understanding of all things C/C++.
extern statements are not meant to only be used in header files referencing other header files (ie. in "B.h" writing extern int a where a is defined in "A.c") but also in the original header files (in this case "A.h")
I thought, incorrectly, that a definition needed an equals sign (ie. int a = 1) whereas int a is also a definition. I was, thus, defining my variable in "A.h" when I should have been declaring it like so extern int a in "A.h".
After fixing the above 2, I kept getting undefined reference to a (I literally thought the compiler and linker were taking the piss). I was searching for int a=... in "A.cpp" and as clear as day it was being defined. Turns out this definition was inside a function, and therefore was never being defined.
If all else fails, edit your source files in a trivial way (ie. delete a word and type it again) to force a compilation) as I find changing the header files does not always result in full compilations.
Related
I am learning C++ and I am confused by inline behavior. On cppreference I found that " function included in multiple source files must be inline". Their example is the following:
// header file
#ifndef EXAMPLE_H
#define EXAMPLE_H
// function included in multiple source files must be inline
inline int sum(int a, int b)
{
return a + b;
}
#endif
// source file #2
#include "example.h"
int a()
{
return sum(1, 2);
}
// source file #1
#include "example.h"
int b()
{
return sum(3, 4);
}
This is a bit confusing to me - I thought that the ifndef guard was doing this job exactly, i.e. preventing problems when the same file was included multiple times. In any case, I wanted to test this, so I prepared the following:
// Sum.h
#ifndef SUM_H
#define SUM_H
int sum(int a, int b);
#endif
// Sum.cpp
int sum(int a, int b){
return a + b;
}
// a.h
#ifndef A_H
#define A_H
int af();
#endif
// a.cpp
#include "sum.h"
int af(){
return sum(3, 4);
}
// b.h
#ifndef B_H
#define B_H
int bf();
#endif
// b.cpp
#include "sum.h"
int bf(){
return sum(1, 2);
}
// main.cpp
#include "sum.h"
#include "a.h"
#include "b.h"
#include <iostream>
int main() {
std::cout << af() + bf();
}
And this works fine as expected. Then I use define the sum function to be inline in sum.cpp and sum.h, and it fails to compile:
"sum(int, int)", referenced from:
bf() in b.cpp.o
af() in a.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Can somebody clarify this for me?
The include guard with #ifndef/#define/#endif or with #pragma once only prevents the inclusion for every single translation unit.
Lets assume you have a header like:
#pragma once
void Do() {}
and two *.cpp files which do the include. If you now compile with
g++ source1.cpp source2.cpp
you will get a
multiple definition of Do() in xy line/file
Every source file will compiled "alone" and so the guard is not seen from the second translation unit which was set by the first one. Both translations ( compilations ) are done fully independent. As this, the include guard will not protect anything in this case.
For this it is possible to define a function definition as inline. Now both definitions will be presented to the linker but marked as "weak". The linker now did not complain about the two definitions and only takes one of them ( typically the last! ) which is not important, as both are the same in that case.
So the include guard has the sense, that you can include a file multiple times to one translation unit. This will happen typically only if you indirect include a header. Lets say a.h has the function definition and b.h and c.h each include a.h. If your cpp-file includes now b.h and c.h both of them include a.h. So you have, without include guard, multiple definitions. This is the use case for include guards.
And the opposite problem having a "undefined symbol" if the function is defined inline but not visible in all using translation units:
Example:
Having that file:
inline void sum() {}
void f1() { sum(); }
and compile with -O0 produces, output of nm f1.o|c++filt
0000000000000000 T f1()
0000000000000000 W sum()
We see the symbol for sum defined as weak, so it can be present multiple times in link stage. It will also be used if a second translation unit which did not "see" the definition, will be linked without problems.
But using "-O3" you get:
0000000000000000 T f1()
That is implementation specific to the compiler! A compiler can provide inlined functions. Typically they do not, if higher optimization levels are in use.
As a rule: If a function is defined inline, its definition must be visible to every translation unit before it is used there!
Then I use define the sum function to be inline in sum.cpp and sum.h, and it fails to compile:
When a function is declared inline, its definition must be available in all the translation units that use the function. Defining the function in only one translation unit is not correct. That's why you are seeing the linker errors.
Move the definition of the function to sum.h to resolve the linker errors.
You should read documentation carefully, beside the statement:
function included in multiple source files must be inline
it also says this:
2) The definition of an inline function or variable (since C++17) must be present in the translation unit where it is accessed (not necessarily before the point of access).
which you violated in your example hense the error.
First of all I know this isnt "correct." However, I like to test things out and I have run into this problem that if I create a global variable in the header file and declare it extern in the main.cpp file, I can use it(Note that I did not include the class header on this example). However, if I actually try to do the same thing, the only difference being including the class header, I get an error.
(error: ld returned 1 exit status).
I wonder why this happens?
Code as requested:
Main.cpp:
#include <iostream>
#include "albino.h"
using namespace std;
extern int iVar;
int main()
{
cout << iVar << endl;
}
albino.h:
#ifndef ALBINO_H
#define ALBINO_H
int iVar = 10;
class albino
{
public:
albino();
};
#endif // ALBINO_H
The albino.cpp doesnt have anything.
ERROR: ||error: ld returned 1 exit status|
I think you are doing it the wrong way around.
You can define a global variable only once; but you can declare it many times, wherever you want to use it.
That means int i = 0; should only be existing once, so _not in the header, but in exactly one cpp file (doesn't matter for the compiler which one, only for humans that try to find it); and extern int i; can be in the header so it is repeated everywhere.
See also How do I use extern to share variables between source files?
I understand that pre-processor commands are an important part of header files to prevent vars and classes from being defined more than once.
I have been running into issues with my vars being defined multiple times - even with pre-processor wrappers. Here is a sample project that is experiencing compiler errors:
Header:
// TestInclude.h
#ifndef TESTINCLUDE_H_
#define TESTINCLUDE_H_
int myInt;
#endif /*TESTINCLUDE_H_*/
C++:
// TestInclude.cpp
#include <iostream>
#include "IncludeMe.h"
#include "TestInclude.h"
int main( int argc, char* args[] )
{
std::cin >> myInt;
IncludeMe thisClass;
std::cin >> myInt;
}
Header:
// IncludeMe.h
#ifndef INCLUDEME_H_
#define INCLUDEME_H_
class IncludeMe
{
private:
int privateInt;
public:
IncludeMe();
};
#endif /*INCLUDEME_H_*/
C++:
// IncludeMe.cpp
#include <iostream>
#include "IncludeMe.h"
#include "TestInclude.h"
IncludeMe::IncludeMe()
{
std::cout << "myInt: " << myInt;
}
Then I compile like this:
Makefile:
all:
g++ -g -o TestInclude TestInclude.cpp IncludeMe.cpp
And I get the following error:
/tmp/ccrcNqqO.o: In function `IncludeMe':
/home/quakkels/Projects/c++/TestInclude/IncludeMe.cpp:6: multiple definition of `myInt'
/tmp/ccgo6dVT.o:/home/quakkels/Projects/c++/TestInclude/TestInclude.cpp:7: first defined here
collect2: ld returned 1 exit status
make: *** [all] Error 1
Why am I getting this error when I'm using pre-processor conditionals in my header files?
Include guards do not protect against multiple definitions. They only protect against infinite recursive inclusion. (You can of course include the same header in multiple translation units!)
You should never have object definitions* in the header; only declarations:
header.hpp:
extern int a;
file.cpp:
#include "header.hpp"
int a = 12;
*) You can have class definitions in a header file, as well as inline functions and class member functions.
You should use extern int myInt; in header files and only write int myInt; in the single .cpp file where you want to define it.
Some projects use a preprocessor macro like "IN_FOO_CPP" to make that happen automatically with #ifdefs.
Suppose that I have those three files:
a.h
//a.h header
#include <stdio.h>
int int_variable;
void a_f()
{
printf("int_variable: %d\n", int_variable)
int_variable++;
}
b.h
//b.h header
#include <stdio.h>
int int_variable;
void b_f()
{
printf("int_variable: %d\n", int_variable)
int_variable++;
}
main.c
//main.c
#include "a.h"
#include "b.h"
int main()
{
a_f();
b_f();
return 0;
}
Why compiling in C++ generates redefinition error, but in C doesn't?
I am C++ developer, then in C++ makes sense to me, but why in C this is not an error?
When I executed the C generated code, the output was:
int variable: 0
int variable: 1
In C, the two variables are actually combined into a single variable because neither is explicitly initialized.
If you change both your h files to:
// a.h
int int_variable = 0;
and:
// b.h
int int_variable = 0;
you will get a redefinition error.
Global variables in header file should only be used along with the "extern" modifier. No exceptions. Forward declare your variable in one or more header files (preferably just one), then define it in exactly one compilation unit.
If I declare a global variable in a header file and include it in two .cpp files, the linker gives an error saying the symbol is multiply defined.
My question is, why does this happen for only certain types of object (eg. int) and not others (eg. enum)?
The test code I used is given below:
test.h
#ifndef TEST_HEADER
#define TEST_HEADER
namespace test
{
int i_Test1 = -1;
int i_Test2 = -1;
};
#endif // TEST_HEADER
class1.h
#ifndef CLASS_1_HEADER
#define CLASS_1_HEADER
class class1
{
public:
void count();
};
#endif //CLASS_1_HEADER
class1.cpp
#include <iostream>
#include "class1.h"
#include "test.h"
void class1::count()
{
std::cout << test::i_Test1 << std::endl;
}
class2.h
#ifndef CLASS_2_HEADER
#define CLASS_2_HEADER
class class2
{
public:
void count();
};
#endif //CLASS_2_HEADER
class2.cpp
#include "class2.h"
#include <iostream>
#include "test.h"
void class2::count()
{
std::cout << test::i_Test2 << std::endl;
}
main.cpp
#include "class1.h"
#include "class2.h"
int main(int argc, char** argv)
{
class1 c1;
class2 c2;
c1.count();
c2.count();
return -1;
}
Building this code with:
g++ main.cpp class1.cpp class2.cpp -o a
produces the following output:
ld: fatal: symbol test::i_Test1' is
multiply-defined:
(file /var/tmp//ccwWLyrM.o type=OBJT; file /var/tmp//ccOemftz.o
type=OBJT); ld: fatal: symbol
test::i_Test2' is multiply-defined:
(file /var/tmp//ccwWLyrM.o type=OBJT; file /var/tmp//ccOemftz.o
type=OBJT); ld: fatal: File processing
errors. No output written to a
collect2: ld returned 1 exit status
If I change the test.h file as given below:
test.h (with enum)
#ifndef TEST_HEADER
#define TEST_HEADER
namespace test
{
enum val
{
i_Test1 = 5,
i_Test2
};
//int i_Test1 = -1;
//int i_Test2 = -1;
};
#endif // TEST_HEADER
I don't get the "multiply defined" error and the program gives the desired output:
5
6
That's because enumerations are not objects - they are types. Class types (class,struct,union) and enumerations can be defined multiple times throughout the program, provided all definitions satisfy some restrictions (summed up by the so-called One Definition Rule (ODR)). The two most important ones are
All definitions have the same token sequence (textual identical)
Names used must have the same meaning (resolve to the same things) in all definitions. (this is a requirement on the context of the definition)
Your enumeration definition satisfies all conditions of the ODR. Therefor, that is valid and no reason for the linker / compiler to moan (actually, for a violation of the ODR the compiler is not required to issue a message either - most of it falls under the so-called no diagnostic required rule, some violations also result in undefined behavior).
However, for every non-inline function and object, these must be only defined one time. Multiply defining those result in spurious errors, like in your case. To solve it, put only a declaration into the header file (using "extern" without an initializer) and put one definition into one of those .cpp files (omitting the "extern" then, or putting an initializer. If it is a const object, you still need the "extern", since per default const variables have internal linkage, and the symbol would not be exported otherwise).