How to declare global variables in seperate config.h file - c++

I am running into a problem with compiling in VScode and not when in Visual Studio.
I have a header file config.h in the include folder in my project. Please note I have added build_flags = -I include to platformio.ini. In config.h I need to make some declarations for a select number of global variables that I need. Everything else is done with pointers, etc.
The problem I have is two fold.
When declaring a variable for example int myVar in config.h I get a multiple declaration error. Why?
I can declare the variable as extern int myVar. But then I need to redeclare the variable myVar in a .cpp file, like main.cpp. How is this best done?
Ultimately, how can I declare a global variable in a header, include that header in several other files and then use the variable globally? (This is primarily aimed at creating queues and semaphores)

If you just want global constants, refer to Defining global constant in C++. Assuming that you need a mutable global variable, there are two options. In either case, there will be only one instance of our global variable.
Classic Solution: extern
// header file
extern MyQueue queue;
Here, we simply say that queue is defined in some other source file.
// source file
MyQueue queue{1, 2, 3};
And then, we define it in the source file.
Also see cppreference on external linkage
C++17 Solution: inline
// header file (no source file needed)
inline MyQueue queue{1, 2, 3};
inline works the same for functions as it does for variables. It relaxes the one definition rule (ODR) for our variable, allowing us to define it in multiple locations. This way, we don't get any linker errors when including the header in multiple source files.

Related

Understanding C linker error: multiple definition

I have a project with multiple header files and .cpp files.
All of the header files have include guards.
There is a file called Constants.h where I define some constants. Some of these with defines, some as constant variables.
There are more header-.cpp-file pairs with code in them. One of these does contain a class, the others don't.
When I include my files into my main file (an arduino sketch), I get a lot of linker errors, claiming there are multiple definitions of some variables.
I read that this mainly occurs when you include .c or .cpp files, which I don't do. All the .cpp files only include their appropriate header files.
I did manage to find multiple solution proposals:
1) inline:
With functions, inline can be used to get rid of this problem. However, this is not possible with variables.
2) anonymous namespace:
This is one of the solutions I used. I put anonymous namespaces around all the problematic definitions I had. It did work, however I do not understand why this works. Could anyone help me understand it?
3) moving definitions into .cpp files:
This is another approach I used sometimes, but it wasn't always possible since I needed some of my definitions in other code, not belonging to this header file or its code (which I do admit is bad design).
Could anyone explain to me where exactly the problem lies and why these approaches work?
Some of these with defines, some as constant variables.
In C const does not imply the same thing as it does in C++. If you have this:
const int foo = 3;
In a header, then any C++ translation unit that includes the header will have a static variable named foo (the const at namespace scope implies internal linkage). Moreover, foo can even be considered a constant expression by many C++ constructs.
Such is not the case in C. There foo is an object at file scope with external linkage. So you will have multiple definitions from C translation units.
A quick fix would be to alter the definitions into something like this:
static const int foo = 3;
This is redundant in C++ but required in C.
In addition to Story Teller's excellent explanation, to define global variables, use the following:
// module.h
#include "glo.h"
// glo.h
#ifndef EXTERN
# define EXTERN extern
#endif
EXTERN int myvar;
// main.c
#define EXTERN
#include "glo.h"
In main.c all variables will be declared (i.e. space is allocated for them), in all other c files that include glo.h, all variables will be known.
You shouldn't declare any object in header files, this should be moved to c\c++ files.
In header you may:
declare types such as: classes, structs, typedefs etc.
put forward declarations of (not classes) functions
put inline (or in classes) functions (+ body)
you may add extern declaration.
you may put your macros.
a static declaration may declare things multiple times, therefore it is not recommended.

Multiple definition error in Dev-C++ [duplicate]

This question already has answers here:
Multiple definition of a function error, even when using #if guard clauses
(5 answers)
Closed 6 years ago.
I initialised some arrays in a file called Fares.cpp in my project. When I try using #include "Fares.cpp" in my main.cpp file (where the main code for the project is) in Dev-C++, the compiler gives an error saying “multiple definition”. I don't know what to do, please help.
I don’t know much about macros, extern etc.
Try including "Fares.h" instead of "Fares.cpp". #include is usually used to include header files which usually contain variable declarations and function prototypes. Check this link for more info: http://www.learncpp.com/cpp-tutorial/19-header-files/
Traditionally, .c and .cpp files are related to single compile unit (module, etc.), processed by compiler separately. Include meant to add files called "header files" or "include files" to the file scope, making declarations, inline functions definitions and type definitions in them being available to syntax analyzer of compiler.
Declarations include:
Function declaration
Template declaration
Explicit template instantiation
Explicit template specialization
Namespace definition
Linkage specification
Attribute declaration (attr ;) (since C++11)
Empty declaration (;) (since C++11)
To avoid multiple definition of same classes or functions, header files must use #ifndef blocks as "brackets"
// beginning of file.h
#ifndef SOME_UNIQUE_ID
#define SOME_UNIQUE_ID
// declarations , etc.
#endif
// end of file .h
There is nothing that prevents use of different suffixes, it's matter of how build process is organized. There is common agreement to name C files .c, C++ - .cpp, standard C++ headers wouldn't have suffix at all, while all other headers may have .h or .hpp. Include files that contain only inline functions sometimes are given .inc or .inl suffix instead of .h, but this isn't regulated in any way as far as I know
You can have only one definition per same scope with same ID. More of even while you may have several file scopes, for each .cpp a non-static declaration would generate duplicate IDs that would cause link-time error. You really should avoid using .cpp as include file, because in most build environments compiler would attempt to link it multiple times - for each use in #include and as separate module as well.
In your case you should put declarations of your arrays into .h file in form like this:
// fares.h
#ifndef FARES_H_
#define FARES_H_ // this will not allow declaration to be repeated
extern int gYourGlobalArray[100];
#endif
Word extern will tell the compiler that the symbol is defined elsewhere and would be found on link stage, the object should be static or thread storage duration, which in our case true as we declare global variable, and gets external linkage. Fares.cpp will have "implementation" that must contain symbols that will not be repeated.
// Fares.cpp
#include "fares.h" // necessary only if you require something declared there
// keep in mind that some file systems are case sensitive, some aren't and
// will not distinguish between Fares.h and fares.h
int gYourGlobalArray[100] = {};
That's actually defines thread duration storage for your array in file scope and allows it to be linked externally. Across entire project its identification should be unique (C++ compiler mangles names of some objects, e.g. functions, but in general you should avoid reusing IDs). If for some wild reasons ID in file scope repeats in different files but should not be linked externally, such storage should be declared static, that would disallow external linkage.
Declaring a static member of class usually either require similar definition in .cpp file (without keyword static) or requires initialization within class body, provided compiler supports that.
Next you only should add fares.cpp to your project\makefile\whatever you are using as compiling environment. fares.h goes into #include statements into .cpp or .h files that require it. #include statement technically just adds text of mentioned file to file wrote it in, exactly in that position.

LNK1169 and LNK2005 Errors

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++.

Why can't a non-static variable reside in a header file?

Take for example:
// myheader.h
static int myStaticVar = 0;
// If we remove 'static' the compiler will throw linker error.
void DoStuff();
// and myheader.cpp, and main.cpp; etc
This is how I would explain it:
Static variables do not have external linkage, and when we compile
without 'static' we are "including" the static variable (which is
global here) in every file, which create duplicates and linker will
throw an error since multiple declaration is not allowed.
Is there any better way to explain this? Thanks.
PS: Are we suppose to have static variables (not talking about members) in header file?
Why can't a non-static variable reside in a header file?
Because it breaks the One Definition Rule(ODR).
When you include the header file containing a non-static variable, the declaration of the variable gets pasted in each source file where it is included. Thus you end up having more than one definition of a variable in same Translation Unit, this violates the ODR and hence the linker will give you linking errors.
How to explain static variables declared in header files?
When you declare a static variable in an header file, an copy of the variable gets created in each Translation Unit where the header file is included.
Declaring a static variable in header file will not give you multiple definition erros but it does not acheive your purpose of having a global variable whose value is shared accross all files which access it.
You may think that since you are using a global static variable its value will be retained accross different files, but as mentioned above each Translation Unit has its own copy of the variable and it does not acheive what you think you are acheiving.
Are we suppose to have static variables (not talking about members) in header file?
No,Never!
How do you declare and define global variables?
You need to use extern keyword.
Add the extern declaration of the variable in an header file. The header should be included by the one source file that defines the variable and by all the source files that reference the variable. Only one source file should define the variable. Also only one header file should declare the variable.
filename.h
extern int gVariable; /* Declaration */
file1.cpp
#include "filename.h"
/* Definition */
int gVariable = 37;
void doSomething(void)
{
return gVariable++;
}
file2.cpp
#include "filename.h"
#include <stdio.h>
void doSomethingWithGlobal(void)
{
printf("Global variable: %d\n", gVariable++);
}
First, read this answer to a similar question.
To complement the answer based on your question, here goes:
When you #include a file (any file, .h files is a common convention), it almost basically just copy-pastes it in your code. If you have non-static variable in the header file and you include it in two source files, the variable gets copy-pasted in both source files and well you get a link error as I explained in the answer I told you to read above.
If you want to share a global variable across many source files, you should do this:
In only one of your source files:
type global_var = default_value;
In the header file:
extern type global_var;
So, this way, all the source files see there is going to be a global_var somewhere in the bunch of source files. Only one of the source files actually contains that variable and when linking happens, all the source files would be referring to that one instance of global_var
The header file (.h) tells you (declares) what the definition file (.cpp) will do.
For a metaphor - a header file is like to telling a lot of friends that you are going to do something, but in reality you are going to do it once.

Header Guards and LNK4006

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...