In my C++ project ,when i declare a global variable in my header file,i get LNK2005(x is already defined in y.obj) and LNK1169(one or more multiply defined symbols found z.exe) errors in visual studio 2012,but when i declare the global variable with const identifier,i do not get an error.From my research in msdn i understand that it is because of project properties.But i can not fix them with properties.It is only fixed with const identifier.But i can not find any rules about it in C++.is it a new feature in C++11???
This is a declaration of a global variable:
extern int my_global;
Thie is a definition of a global variable:
int my_global;
A declaration of a global variable says "here is the name of an object". A definition says "here is the name of an object, and please allocate storage space for it".
You can have as many declarations of a global variable as you want (so that anyone in any source file can refer to that same object), but you can only have one definition, since the object can only exist in one place in memory when the program runs.
The linker is complaining that you have multiple definitions of the same object because you're putting a definition in the header file, and that header gets included in multiple source files. So when, those source files get compiled, you get multiple definitions, and the linker can't do that.
The solution is to put only a declaration in the header file, and then put the definition in exactly one source file. For example:
// MyVariables.h
extern int my_global;
// MyVariables.cpp
int my_global = 42;
The reason you're seeing different behavior with the const keyword is because the const gives global variables internal linkage, meaning they're not visible to other source files. In effect, these means that each source file that includes your header gets its own copy of the constant. This takes up a little more memory, but it's not going to be noticeable. And since it's a constant, nobody's going to notice that the different constants refer to different locations in memory.
C++11 did not change any of this behavior. These constructs all behaved the same way in previous versions of C++.
Related
How do we make a variable global across over all .cpp files/modules of a (will-be) single binary, which is to be compiled and linked by g++ in a line?
even if it's been defined in main and has extern in var. to be included in every .cpp
extern int a_sample_var;
tried it for more a week only to fail,
.....: undefined reference to a_sample_var .....
Any generous guru helping me out?
extern int a_sample_var;
Tells the compiler: there is a int named a_simple_var defined somewhere else (think about the keyword extern: it's abbreviation for external, meaning "somewhere else"). Just leave a placeholder there and wait for the linker to find it!
Well if you do this in every cpp file (by including a header), then everyone is crying for the definition (by providing a declaration), but with no one to provide the definition. Be aware of the wording here, definition and declaration are different stuff.
In exactly one cpp file, you shall provide a definition of a_simple_var. Just simply remove the extern:
int a_sample_var; // Initialize with 0
or
int a_sample_var = 1; // Initialize with 1.
Those two are proper definitions.
Learning from this: By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
But if I write this inside MyTools.h:
#ifndef _TOOLSIPLUG_
#define _TOOLSIPLUG_
typedef struct {
double LN20;
} S;
S tool;
#endif // !_TOOLSIPLUG_
and I include MyTools.h 3 times (from 3 different .cpp) it says that tool is already defined (at linker phase). Only if I change in:
extern S tool;
works. Isn't external default?
The declaration S tool; at namespace scope, does declare an extern linkage variable. It also defines it. And that's the problem, since you do that in three different translation units: you're saying to the linker that you have accidentally named three different global variables, of the same type, the same.
One way to achieve the effect you seem to desire, a single global shared variable declared in the header, is to do this:
inline auto tool_instance()
-> S&
{
static S the_tool; // One single instance shared in all units.
return the_tool;
}
static S& tool = tool_instance();
The function-accessing-a-local-static is called a Meyers' singleton, after Scott Meyers.
In C++17 and later you can also just declare an inline variable.
Note that global variables are considered Evil™. Quoting Wikipedia on that issue:
” The use of global variables makes software harder to read and understand. Since any code anywhere in the program can change the value of the variable at any time, understanding the use of the variable may entail understanding a large portion of the program. Global variables make separating code into reusable libraries more difficult. They can lead to problems of naming because a global variable defined in one file may conflict with the same name used for a global variable in another file (thus causing linking to fail). A local variable of the same name can shield the global variable from access, again leading to harder-to-understand code. The setting of a global variable can create side effects that are hard to locate and predict. The use of global variables makes it more difficult to isolate units of code for purposes of unit testing; thus they can directly contribute to lowering the quality of the code.
Disclaimer: code not touched by compiler's hands.
There's a difference between a declaration and a definition. extern int i; is a declaration: it says that there's a variable named i whose type is int, and extern implies that it will be defined somewhere else. int i;, on the other hand, is a definition of the variable i. When you write a definition, it tells the compiler to create that variable. If you have definitions of the same variable in more than one source file, you've got multiple definitions, and the compiler (well, in practice, the linker) should complain. That's why putting the definition S tool; in the header creates problems: each source file that #include's that header ends up defining tool, and the compiler rightly complains.
The difference between a const and a not-const definition is, as you say, that const int i = 3; defines a variable named i that is local to the file being compiled. There's no problem having the same definition in more than one source file, because those guys all have internal linkage, that is, they aren't visible outside the source file. When you don't have the const, for example, with int i = 3;, that also defines a variable named i, but it has external linkage, that it, it's visible outside the source file, and having the same definition in multiple files gives you that error. (technically, it's definitions of the same name that lead to problems; int i = 3; and double i = 3.0; in two different source files still are duplicate definitions).
By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
That statement is still correct in your case.
In your MyTools.h, tool is external.
S tool; // define tool, external scope
In your cpp file, however, the extern keyword merely means that S is defined else where.
extern S tool; // declare tool
I have a header file that has a number of declarations like this:
extern ID3D10Device* device;
I can't make these static because of a problem with multiple translation units, and I can't have them as normal pointers for a similar reason. However when I try to build the program I get unresolved external symbol linker errors. I'm assuming that this is because I'm attempting to use the pointers without defining them first. This is the problem however, as the way you initialise these DirectX objects is by passing the address of the pointers as parameters into specialist methods. - I may be wrong but I am assuming this is the problem as the compiler / linker / whatever can't see the definitions.
All I'm trying to do is have these pointers (for the graphics device, depth buffer etc) visible to multiple classes. How can this be achieved?
You need the pointers to be defined in some translation unit. The linker is complaining because it seems you haven't done that anywhere. You should declare them at file scope as
ID3D10Device* device = NULL;
in the source file where you call the DirectX function that initializes them. Just make sure the declaration is only made in one source file, then the extern statement should be placed in the associated header file which is included by all translation units that need to use these pointers.
When you externally define a variable like this, the compiler is not reserving any memory for that variable until it sees a definition inside a code module itself. So if you are going to be passing these pointers by-reference to a function for initializing their values, they must be defined in a code module somewhere.
You only need to define them in a single code module ... then place the extern declarations inside a header file you include in the rest of your code modules that require access to the pointer variables. That shouldn't create any linker errors due to duplicate definitions.
I can't make these static because of a problem with multiple translation units
If you need a different variable in different TU (translation units), make it static: this way the variable will be specific to each TU.
A declaration of a variable is also definition unless the extern is used.
You must have one (and only one) definition of a variable in the program.
To have a global variable:
Declare it with the extern keyword in some header file.
Include this header in every TU that needs to use the variable. Never declare the variable directly, never bypass the header inclusion.
Define the variable: a declaration without the extern keyword will define the variable in one TU. You need to include the header file in the same TU to guaranty consistency between the extern declaration and the definition.
the way you initialise these DirectX objects is by passing the address
of the pointers as parameters into specialist methods
To solve this part of the problem, you could do something like this (in a .cpp file):
ID3D10Device* device;
struct Foo {
Foo(ID3D10Device **pdevice) { specialist_method(pdevice); }
};
Foo f(&device);
Beware of the "static initialization order fiasco", though -- it's safe to use device from main, or code called from main, because it will definitely be initialized before that code executes. It's not necessarily safe to use it from other initializers executed before main, because the order of initialization of statics in different translation units is unspecified (within a TU, they're initialized in order of either declaration or definition, I forget which). So device might still be a null pointer in that code. Likewise, specialist_method can't necessarily rely on other statics having been initialized.
There are extra tricks you can use if you need to enforce initialization orders, I'd guess that all the common ones are on SO already in other questions.
How does the following example usage of extern specifer behave.
We have a global variable int x both in files one.c and two.c
We want to use these in three.c so have declared this variable in three.c as
extern int x;
What would happen when we compile and link these files?
My answer is: compilation of all these files should succeed, however the linker should flag an error at linking, due to multiple declarations of x.
Would there be any difference in behavior in C++ ?
Is these any way to refer to int x (in three.c) simultaneously from both files, in C and C++.
In C++, I guess we can use namespaces to acheive this. Right?
By default, global variables have external linkage, which means that they can be used by other source files (or "translation units"). If you instead declare your global variables with the static keyword, they will have internal linkage, meaning they will not be usable by other source files.
For variables with external linkage, you can't have multiple variables with the same name, or the linker will complain. You can have two variables with the same name, though, as long as at least one has internal linkage, and of course you can't reference both of them in the same source file.
An extern declaration is just saying to the compiler "here is the name of some variable with external linkage defined in another translation unit," allowing you to refer to that variable.
C++ is exactly the same, except for the addition of namespaces. If global variables are put inside a namespace, then they can have the same name without linker errors, provided they are in different namespaces. Of course, all references to those variables then have to either refer to the full name namespace::var_name, or use a using declaration to establish a local namespace context.
C++ also has anonymous namespaces, which are entirely equivalent to using the static keyword for global variables in C: all variables and functions declared inside an anonymous namespace have internal linkage.
So, to answer your original question, you are right -- compilation would succeed, but linking would fail, due to multiple definitions of the variable x with external linkage (specifically, from the translation units one.c and two.c).
From three.c, there is no way to refer simultaneously to both variables x. You'll need to rename x in one or both modules, or switch to C++ and put at least one x inside a namespace.
In C, you could do this:
// one.c
static int x;
int *one_x = &x;
// two.c
static int x;
int *two_x = &x;
// three.c
extern int *one_x;
extern int *two_x;
Now you can refer unambiguously to the x in file one.c or the x in file two.c from the file three.c.
However, this might be a bit more effort than it's worth. Perhaps you should be coming up with more descriptive names for your global variables instead of toying around with theoretical ways to circumvent C's single global namespace.
To avoid generating duplicate symbols, you should declare extern int x; in a single header file (a .h file), and then have all .c files which will use x #include that header file, and define or initialize int x; in one of the .c files.
You might be interested by the answers to this question.
Summary: the linker may or may not fail to link the file. It depends on the initialization of the variable. It will definitely fail if the variable has different initializations in different files.
Remember that you can NOT extern a global static variable.. !!
I have a character array defined in a header
//header.h
const char* temp[] = {"JeffSter"};
The header if #defined guarded and has a #pragma once at the top. If this header is included in multiple places, I get an LNK4006 - char const * * temp already defined in blahblah.obj. So, I have a couple of questions about this
Why does this happen if I have the guards in place? I thought that they prevented the header from being read in after the first access.
Why do the numerous enums in this header not also give the LNK4006 warnings?
If I add static before the signature, I don't get the warning. What are the implications of doing it this way.
Is there a better way to do this that avoids the error, but lets me declare the array in the header. I would really hate to have a cpp file just for an array definition.
Why does this happen if I have the guards in place? I thought that they prevented the header from being read in after the first access.
Include guards make sure that a header is included only once in one file (translation unit). For multiple files including the header, you want the header to be included in each file.
By defining, as opposed to declaring variables with external linkage (global variables) in your header file, you can only include the header in once source file. If you include the header in multiple source files, there will be multiple definitions of a variable, which is not allowed in C++.
So, as you have found out, it is a bad idea to define variables in a header file for precisely the reason above.
Why do the numerous enums in this header not also give the LNK4006 warnings?
Because, they don't define "global variables", they're only declarations about types, etc. They don't reserve any storage.
If I add static before the signature, I don't get the warning. What are the implications of doing it this way.
When you make a variable static, it has static scope. The object is not visible outside of the translation unit (file) in which it is defined. So, in simple terms, if you have:
static int i;
in your header, each source file in which you include the header will get a separate int variable i, which is invisible outside of the source file. This is known as internal linkage.
Is there a better way to do this that avoids the error, but lets me declare the array in the header. I would really hate to have a cpp file just for an array definition.
If you want the array to be one object visible from all your C++ files, you should do:
extern int array[SIZE];
in your header file, and then include the header file in all the C++ source files that need the variable array. In one of the source (.cpp) files, you need to define array:
int array[SIZE];
You should include the header in the above source file as well, to allow for catching mistakes due to a difference in the header and the source file.
Basically, extern tells the compiler that "array is defined somewhere, and has the type int, and size SIZE". Then, you actually define array only once. At link stage, everything resolves nicely.
Include guards protect you from including the same header into the same file repeatedly - but not from including it in distinct files.
What happens is that the linker sees temp in more then one object file - you can solve that by making temp static or putting it into an unnamed namespace:
static const char* temp1[] = {"JeffSter"};
// or
namespace {
const char* temp2[] = {"JeffSter"};
}
Alternatively you can use one source file which defines temp and just declare it as extern in the header:
// temp.cpp:
const char* temp[] = {"JeffSter"};
// header.h:
extern const char* temp[];
Header guards have absolutely nothing to do with preventing multiple definitions in your entire program. The purpose of header guards is to prevent multiple inclusion of the same header file into the same translation unit (.cpp file). In other words, they exist to prevent multiple definitions in the same source file. And they do work as intended in your case.
The rule that governs multiple-definition issues in C++ is called One Definition Rule (ODR). ODR is defined differently for different kinds of entities. For example, types are allowed to have multiple identical definitions in the program. They can (and most always have to) be defined in every translation unit where they are used. This is why your enum definition does not result in an error.
Objects with external linkage are a completely different story. They have to be defined in one and only one translation unit. This is why your definition of temp causes an error when you include the header file into multiple translation units. Include guards can't prevent this error. Just don't define objects with external linkage in header files.
By adding static you give your object internal linkage. This will make the error disappear, since now it is perfectly OK from ODR point of view. But this will define an independent temp object in each translation unit into which your header file is included. To achieve the same effect you could also do
const char* const temp[] = { "JeffSter" };
since const objects in C++ have internal linkage by default.
This depends on whether you need an object with external linkage (i.e. one for the entire program) or an object with internal linkage (unique to each translation unit). If you need the latter, use static and/or extra const (if that works for you) as shown above.
If you need the former (external linkage), you should put a non-defining declaration into the header file
extern const char* temp[];
and move the definition into one and only one .cpp file
char* const temp[] = { "JeffSter" };
The above declaration in the header file will work for most purposes. However, it declares temp as an array of unknown size - an incomplete type. If you wish to declare it as an array of known size, you have to specify the size manually
extern const char* temp[1];
and remember to keep it in-synch between the declaration and definition.
I respectfully disagree with the advice against defining variables in headers, because I think "never" is too broad. Nevertheless, the episode that brought me to this thread offers a cautionary tale for those who dare to do so.
I landed on this page as the result of an inquiry into the cause of warning LNK4006, calling out a long established array that I just moved from the translation unit that defines my DLLMain routine into the private header that is included in most of the translation units that comprise this library. I have compiled this library hundreds of times over the last 11 years, and I had never before seen this warning.
Shortly after I read this page, I discovered the cause of the error, which was that the definition was outside the guard block that protects everything else that is defined in the module that also defines DLLMain, which is where I usually gather all the memory blocks that need external linkage. As expected, moving the table inside the guard block eliminated the warnings, leaving me with only two, related to a brand new externally linked table, to be resolved.
Takeaway: You can define variables in headers, and it's a great place to put common blocks, but mind your guards.
Hang on... you are mixing up your declarations...you did say 'char const * * temp' yet in your header file you have 'const char* temp[] = {"JeffSter"};'.
See section 6.1 of the C FAQ, under 'Section 6. Arrays and Pointers', to quote:
6.1: I had the definition char a[6] in one source file, and in
another I declared extern char *a. Why didn't it work?
A: In one source file you defined an array of characters and in the
other you declared a pointer to characters. The declaration
extern char *a simply does not match the actual definition.
The type pointer-to-type-T is not the same as array-of-type-T.
Use extern char a[].
References: ISO Sec. 6.5.4.2; CT&P Sec. 3.3 pp. 33-4, Sec. 4.5
pp. 64-5.
That is the source of the problem. Match up your declaration and definitions. Sorry if this sounds blunt, but I could not help noticing what the linker was telling you...