Related
After reading the accepted answer from this question, I thought I understood why the program failed, since the using directive does not actually declare the entity i in the region. However names introduced by a using declaration can be used just like any other name and acts like a declaration.
With GCC, this fails
#include <iostream>
namespace X { int i = 1; }
using X::i;
int main() {
extern int i;
i = 2;
std::cout<<i;
}
But this is accepted
#include <iostream>
int i;
int main() {
extern int i;
i = 2;
std::cout<<i;
}
Technically, the example you've given does compile, but it fails to link. The issue is the line
extern int i;
What you're telling the compiler/linker here is "there will be a variable i defined somewhere else in the program, so, compiler, don't worry if you can't find the definition. Linker, I expect you to find the definition of i once you have all of the object files and link that in here."
We can see this in action using compiler explorer:
Without the extern declaration
With the extern declaration
In the second case, the declaration of i "shadows" the X::i which is visible at global scope, so we get the instruction
mov DWORD PTR i[rip], 2
whereas without the extern declaration, we get
mov DWORD PTR X::i[rip], 2
though I'm not totally sure on the shadowing part, as neither gcc nor clang warns about that with -Wshadow. In any case, we see now why the second example fails to link: the linker is trying to find the definition of i to use here, and while X::i is defined at global scope, i is not.
I have 2 files, A.cpp and B.cpp, in a Win32 console application.
Both 2 files contain only the following 2 lines of code:
#include "stdafx.h"
int k;
When compiling it produces the error
Error 1 error LNK2005: "int k" (?a##3HA) already defined in A.obj
I don't understand what is happening.
Can someone please explain this to me?
Why this error?
You broke the one definition rule and hence the linking error.
Suggested Solutions:
If you need the same named variable in the two cpp files then You need to use Nameless namespace(Anonymous Namespace) to avoid the error.
namespace
{
int k;
}
If you need to share the same variable across multiple files then you need to use extern.
A.h
extern int k;
A.cpp
#include "A.h"
int k = 0;
B.cpp
#include "A.h"
//Use `k` anywhere in the file
In the Project’s Settings, add /FORCE:MULTIPLE to the Linker’s Command Line options.
From MSDN: "Use /FORCE:MULTIPLE to create an output file whether or not LINK finds more than one definition for a symbol."
If you want both to reference the same variable, one of them should have int k;, and the other should have extern int k;
For this situation, you typically put the definition (int k;) in one .cpp file, and put the declaration (extern int k;) in a header, to be included wherever you need access to that variable.
If you want each k to be a separate variable that just happen to have the same name, you can either mark them as static, like: static int k; (in all files, or at least all but one file). Alternatively, you can us an anonymous namespace:
namespace {
int k;
};
Again, in all but at most one of the files.
In C, the compiler generally isn't quite so picky about this. Specifically, C has a concept of a "tentative definition", so if you have something like int k; twice (in either the same or separate source files) each will be treated as a tentative definition, and there won't be a conflict between them. This can be a bit confusing, however, because you still can't have two definitions that both include initializers--a definition with an initializer is always a full definition, not a tentative definition. In other words, int k = 1; appearing twice would be an error, but int k; in one place and int k = 1; in another would not. In this case, the int k; would be treated as a tentative definition and the int k = 1; as a definition (and both refer to the same variable).
Assuming you want 'k' to be a different value in different .cpp files (hence declaring it twice), try changing both files to
namespace {
int k;
}
This guarantees that the name 'k' uniquely identifies 'k' across translation units. The old version static int k; is deprecated.
If you want them to point to the same value, change one to extern int k;.
Both files define variable k as an integer (int).
As a result, the linker sees two variables with the same name, and is unsure which one it should use if you ever refer to k.
To fix this, change one of the declarations to:
extern int k;
That means: "k is an integer, declared here, but defined externally (ie. the other file)."
Now there is only one variable k, that can be properly referred to by two different files.
And if you want these translation units to share this variable, define int k; in A.cpp and put extern int k; in B.cpp.
Presence of int k; in the header file causes symbol k to be defined within each translation unit this header is included to while linker expects it to be defined only once (aka One Definition Rule Violation).
While suggestion involving extern are not wrong, extern is a C-ism and should not be used.
Pre C++17 solution that would allow variable in header file to be defined in multiple translation units without causing ODR violation would be conversion to template:
template<typename x_Dummy = void> class
t_HeaderVariableHolder
{
public: static int s_k;
};
template<typename x_Dummy> int t_HeaderVariableHolder<x_Dummy>::s_k{};
// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
return t_HeaderVariableHolder<>::s_k;
}
With C++17 things become much simpler as it allows inline variables:
inline int g_k{};
// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
return g_k;
}
The linker tells you that you have the variable k defined multiple times. Indeed, you have a definition in A.cpp and another in B.cpp. Both compilation units produce a corresponding object file that the linker uses to create your program. The problem is that in your case the linker does not know whic definition of k to use. In C++ you can have only one defintion of the same construct (variable, type, function).
To fix it, you will have to decide what your goal is
If you want to have two variables, both named k, you can use an anonymous namespace in both .cpp files, then refer to k as you are doing now:
.
namespace {
int k;
}
You can rename one of the ks to something else, thus avoiding the duplicate defintion.
If you want to have only once definition of k and use that in both .cpp files, you need to declare in one as extern int k;, and leave it as it is in the other. This will tell the linker to use the one definition (the unchanged version) in both cases -- extern implies that the variable is defined in another compilation unit.
I'm reading "Think in C++" and it just introduced the extern declaration. For example:
extern int x;
extern float y;
I think I understand the meaning (declaration without definition), but I wonder when it proves useful.
Can someone provide an example?
This comes in useful when you have global variables. You declare the existence of global variables in a header, so that each source file that includes the header knows about it, but you only need to “define” it once in one of your source files.
To clarify, using extern int x; tells the compiler that an object of type int called x exists somewhere. It's not the compilers job to know where it exists, it just needs to know the type and name so it knows how to use it. Once all of the source files have been compiled, the linker will resolve all of the references of x to the one definition that it finds in one of the compiled source files. For it to work, the definition of the x variable needs to have what's called “external linkage”, which basically means that it needs to be declared outside of a function (at what's usually called “the file scope”) and without the static keyword.
header:
#ifndef HEADER_H
#define HEADER_H
// any source file that includes this will be able to use "global_x"
extern int global_x;
void print_global_x();
#endif
source 1:
#include "header.h"
// since global_x still needs to be defined somewhere,
// we define it (for example) in this source file
int global_x;
int main()
{
//set global_x here:
global_x = 5;
print_global_x();
}
source 2:
#include <iostream>
#include "header.h"
void print_global_x()
{
//print global_x here:
std::cout << global_x << std::endl;
}
It is useful when you share a variable between a few modules. You define it in one module, and use extern in the others.
For example:
in file1.cpp:
int global_int = 1;
in file2.cpp:
extern int global_int;
//in some function
cout << "global_int = " << global_int;
It's all about the linkage.
The previous answers provided good explanations about extern.
But I want to add an important point.
You ask about extern in C++, not in C and I don't know why there is no answer mentioning the case when extern comes with const in C++.
In C++, a const variable has internal linkage by default (not like C).
So this scenario will lead to linking error:
Source 1 :
const int global = 255; //wrong way to make a definition of global const variable in C++
Source 2 :
extern const int global; //declaration
It needs to be like this:
Source 1 :
extern const int global = 255; //a definition of global const variable in C++
Source 2 :
extern const int global; //declaration
This is useful when you want to have a global variable. You define the global variables in some source file, and declare them extern in a header file so that any file that includes that header file will then see the same global variable.
I have 2 files, A.cpp and B.cpp, in a Win32 console application.
Both 2 files contain only the following 2 lines of code:
#include "stdafx.h"
int k;
When compiling it produces the error
Error 1 error LNK2005: "int k" (?a##3HA) already defined in A.obj
I don't understand what is happening.
Can someone please explain this to me?
Why this error?
You broke the one definition rule and hence the linking error.
Suggested Solutions:
If you need the same named variable in the two cpp files then You need to use Nameless namespace(Anonymous Namespace) to avoid the error.
namespace
{
int k;
}
If you need to share the same variable across multiple files then you need to use extern.
A.h
extern int k;
A.cpp
#include "A.h"
int k = 0;
B.cpp
#include "A.h"
//Use `k` anywhere in the file
In the Project’s Settings, add /FORCE:MULTIPLE to the Linker’s Command Line options.
From MSDN: "Use /FORCE:MULTIPLE to create an output file whether or not LINK finds more than one definition for a symbol."
If you want both to reference the same variable, one of them should have int k;, and the other should have extern int k;
For this situation, you typically put the definition (int k;) in one .cpp file, and put the declaration (extern int k;) in a header, to be included wherever you need access to that variable.
If you want each k to be a separate variable that just happen to have the same name, you can either mark them as static, like: static int k; (in all files, or at least all but one file). Alternatively, you can us an anonymous namespace:
namespace {
int k;
};
Again, in all but at most one of the files.
In C, the compiler generally isn't quite so picky about this. Specifically, C has a concept of a "tentative definition", so if you have something like int k; twice (in either the same or separate source files) each will be treated as a tentative definition, and there won't be a conflict between them. This can be a bit confusing, however, because you still can't have two definitions that both include initializers--a definition with an initializer is always a full definition, not a tentative definition. In other words, int k = 1; appearing twice would be an error, but int k; in one place and int k = 1; in another would not. In this case, the int k; would be treated as a tentative definition and the int k = 1; as a definition (and both refer to the same variable).
Assuming you want 'k' to be a different value in different .cpp files (hence declaring it twice), try changing both files to
namespace {
int k;
}
This guarantees that the name 'k' uniquely identifies 'k' across translation units. The old version static int k; is deprecated.
If you want them to point to the same value, change one to extern int k;.
Both files define variable k as an integer (int).
As a result, the linker sees two variables with the same name, and is unsure which one it should use if you ever refer to k.
To fix this, change one of the declarations to:
extern int k;
That means: "k is an integer, declared here, but defined externally (ie. the other file)."
Now there is only one variable k, that can be properly referred to by two different files.
And if you want these translation units to share this variable, define int k; in A.cpp and put extern int k; in B.cpp.
Presence of int k; in the header file causes symbol k to be defined within each translation unit this header is included to while linker expects it to be defined only once (aka One Definition Rule Violation).
While suggestion involving extern are not wrong, extern is a C-ism and should not be used.
Pre C++17 solution that would allow variable in header file to be defined in multiple translation units without causing ODR violation would be conversion to template:
template<typename x_Dummy = void> class
t_HeaderVariableHolder
{
public: static int s_k;
};
template<typename x_Dummy> int t_HeaderVariableHolder<x_Dummy>::s_k{};
// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
return t_HeaderVariableHolder<>::s_k;
}
With C++17 things become much simpler as it allows inline variables:
inline int g_k{};
// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
return g_k;
}
The linker tells you that you have the variable k defined multiple times. Indeed, you have a definition in A.cpp and another in B.cpp. Both compilation units produce a corresponding object file that the linker uses to create your program. The problem is that in your case the linker does not know whic definition of k to use. In C++ you can have only one defintion of the same construct (variable, type, function).
To fix it, you will have to decide what your goal is
If you want to have two variables, both named k, you can use an anonymous namespace in both .cpp files, then refer to k as you are doing now:
.
namespace {
int k;
}
You can rename one of the ks to something else, thus avoiding the duplicate defintion.
If you want to have only once definition of k and use that in both .cpp files, you need to declare in one as extern int k;, and leave it as it is in the other. This will tell the linker to use the one definition (the unchanged version) in both cases -- extern implies that the variable is defined in another compilation unit.
I have three programs in which I am using extern keyword. I am not able to understand the result. Below are three examples:
Example 1: I was expecting that below code will give compilation error that multiple declaration of k. But it works fine?
int k; //works fine
extern int k = 10;
void main()
{
cout<<k<<endl;
getchar();
}
Example 2: When I am trying to initialize "k" in above example compiler gives error. Why?
int k = 20; //error
extern int k = 10;
void main()
{
cout<<k<<endl;
getchar();
}
Example 3: In this example I changed the order of definitions mentioned in example 1. When I compile this code I am getting errors. Why?
extern int k = 10;
int k; //error
void main()
{
cout<<k<<endl;
getchar();
}
Example 2: You are trying to initialize a global variable twice, with two different values. This is the error.
Example 3: You first declare an extern variable, and then define a variable with the same name in the same compilation unit. This is not possible.
You should use **extern** keyword the way it meant to be used which is to reference something that is out of the current scope.
You should also follow the rules that works in every compiler and not try to use anomalies of some compiler, your examples gave me lot of errors in my own compiler.
Rules are:
Use extern to reference and not to define a variable.
Use some sort of convention for external naming. I put all my externals as capitals, so when I see something like MYVAR I know its a global.
Put all of your externals in an include header(.h) file and do an #include in your cpp files, this way is more convenient and helps to unclutter your source code.
See this example where I use all 3 rules:
My module1.cpp file:
unsigned short int AGLOBAL = 10; // definer and initializer
void MyFunc(void)
{
AGLOBAL+=1; // no need to include anything here cause is defined above
// more .....
}
My Header file globals.h:
// this is to include only once
#ifndef MYH
#define MYH
extern unsigned short int AGLOBAL; // no value in here!
#endif
Other module2.cpp file:
#include globals.h
char SomeOtherFunc(void)
{
AGLOBAL+=10; // ok cause its declared by globals.h
// do more....
}
The use of extern keyword is to tell the compiler that:
The variable is defined externally.
The first program should give you an error. Which compiler are you using? BTW, void main() is not standard. Neither in C nor in C++.
Your compiler is sloppy. Compiling this trivial variation (including the header and using declaration), I get:
$ cat xxx.cpp
#include <iostream>
using namespace std;
int k; //works fine
extern int k = 10;
void main()
{
cout<<k<<endl;
getchar();
}
$ g++ -c xxx.cpp
xxx.cpp:5:12: warning: ‘k’ initialized and declared ‘extern’ [enabled by default]
xxx.cpp:5:12: error: redefinition of ‘int k’
xxx.cpp:4:5: error: ‘int k’ previously declared here
xxx.cpp:7:11: error: ‘::main’ must return ‘int’
$ g++ --version
g++ (GCC) 4.6.0
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
Which compiler are you using?
int k;
extern int k = 10;
This is ok in C, where you can have a "tentative definition" in addition to the real one. In C++ it is not allowed. There it is an attempt to declare the same variable twice.
My C compiler also warns me that having both extern and an initialization at the same time is unusual.
int k = 20; //error
extern int k = 10;
This attempts to give k two different values, which of course doesn't work.
extern int k = 10;
int k; //error
This seems to be equivalent to case 1. It is not allowed in C++, but seems to be acceptable in C99.
Case 1: Gives an Redefinition Error in c++(gcc-4.3.4)
Case 2: Gives an Redefinition Error in c++(gcc-4.3.4)
Case 3: Gives an Redefinition Error in c++(gcc-4.3.4)
In all the three cases You try to define a variable named k with external linkage and you try to define another variable named k in the same scope, this generates a Redefinition error.
Reference:
C++ Standard: 3.1 Declarations and definitions
3 [Example: all but one of the following are definitions:
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
......
In the above snippet a & c both are definitions.
If your compiler does not give you an error for all the three cases, then it is broken as far as C++ is concerned.
I understand Examples 2 and 3. But the fact that Example 1 was compiled is so weird. gcc would never compiled such code.
For the third one, you really want this
extern int k = 10;
extern int k; //okay: this is just a declaration.
// extern int k = 4; re-define is no good.
void main()
{
cout<<k<<endl;
getchar();
}
You can only define a variable once. You may declare as many times as you like, however.
To indicate a bit further, int i; is both declaration and definition. Often time intiizliation is thought as "definition". For an autotmatic variable, both declaration and definition is done in one single statement.
So when we define int k; memory has been allocated whose name reference is "k". Hence, linker will complain when you try to redefine it.
int k;
extern int k = 3; // already defined in the previous statement
Hence, this is also a compilation error
extern int k = 3;
int k; // trying to redefine again - bad
This is probably applied to only in C++. I am not familiar with C, therefore, I can't speak of C. In C++, even my solution will complain, but will not throw error at it.
Please judge me and correct my mistakes. I am learning also.
First, a nit pick. You are talking about global variable resolution. This is the job of the linker and not the compiler. While it no real implications since all compiler suites are usually executed with the linker as well.
What you should know about global variables is that they are of two kinds: weak and strong. Since there can only be one variable with a given name, if there are multiple definitions, the linker must figure out which one to use. If there are multiple string definitions, then there is an error. If there is a single strong definition then it is chosen as the canonical one and all other definitions refer to it. If there are only weak definitions then one of them gets promoted.
Any declaration where the variable has a value assigned to it is considered strong. Also, if there is no assignment then the extern keyword will force the variable to refer to another variable if one exists (in effect making the weakest of the weak).
Case 1: You have a weak declaration followed by a strong one. This is cool.
Case 2: You have two strong declarations. Error!
Case 3: You have a strong declaration followed by a weak one. I'm not actually sure why this one fails. If I were to guess I would say that the second declaration is being treated as strong by the the linker.