I am new in programming in C, so I am trying many different things to try and familiarize myself with the language.
I wrote the following:
File q7a.h:
static int err_code = 3;
void printErrCode(void);
File q7a.c:
#include <stdio.h>
#include "q7a.h"
void printErrCode(void)
{
printf ("%d\n", err_code);
}
File q7main.c:
#include "q7a.h"
int main(void)
{
err_code = 5;
printErrCode();
return 0;
}
I then ran the following in the makefile (I am using a Linux OS)
gcc –Wall –c q7a.c –o q7a.o
gcc –Wall –c q7main.c –o q7main.o
gcc q7main.o q7a.o –o q7
the output is 3.
Why is this happening?
If you initialize a static variable (in fact any variable) in the header file, so if 2 files include the same header file (in this case q7.c and q7main.c) the linker is meant to give an error for defining twice the same var?
And why isn't the value 5 inserted into the static var (after all it is static and global)?
Thanks for the help.
static means that the variable is only used within your compilation unit and will not be exposed to the linker, so if you have a static int in a header file and include it from two separate .c files, you will have two discrete copies of that int, which is most likely not at all what you want.
Instead, you might consider extern int, and choose one .c file that actually defines it (i.e. just int err_code=3).
When you declared a variable as a static it has only scope within a file ie.., it can be accessed only within a file.
When you declare a static variable in a header file and include this header file in two .c file, then you are creating two different
memory for two different ".c" files
When you print err_code directly in the Main function you would see its value as 5 instead 3,
but you are calling a function printErrCode which is defined in a different file "q7a.c" for which err_code has a different memory location
in which err_code memory is still 3 and it not updated and that is why you are getting the value as 3 instead of 5.
Since two memory is created and err_code is considered as two different variables having different memory with different file scope you will not see any linking errors.
The static variables do not have external linkage which means they cannot be accessed outside the translation unit in which they are being defined. So in your case when q7.h is #include'ed in both translations units q7a.c and q7main.c ... two different copies exists in their corresponding .o files. That is why linker does not report error becuase both copies are not seen by linker while doing external symbol linkage.
While doing small research came to know that we can declare variable in Header file but in one of the source file includes that should have definition for that variable.
Instead if we define a variable in header file. in the source files where this header file included, definitions will be created which causes multiple definitions.
A static variable should be declared with in the file where we use it shouldn't be exposed to header file.
Hope I am giving right information. If I am wrong feel free to correct my statements in your comments.
Related
I am new in programming in C, so I am trying many different things to try and familiarize myself with the language.
I wrote the following:
File q7a.h:
static int err_code = 3;
void printErrCode(void);
File q7a.c:
#include <stdio.h>
#include "q7a.h"
void printErrCode(void)
{
printf ("%d\n", err_code);
}
File q7main.c:
#include "q7a.h"
int main(void)
{
err_code = 5;
printErrCode();
return 0;
}
I then ran the following in the makefile (I am using a Linux OS)
gcc –Wall –c q7a.c –o q7a.o
gcc –Wall –c q7main.c –o q7main.o
gcc q7main.o q7a.o –o q7
the output is 3.
Why is this happening?
If you initialize a static variable (in fact any variable) in the header file, so if 2 files include the same header file (in this case q7.c and q7main.c) the linker is meant to give an error for defining twice the same var?
And why isn't the value 5 inserted into the static var (after all it is static and global)?
Thanks for the help.
static means that the variable is only used within your compilation unit and will not be exposed to the linker, so if you have a static int in a header file and include it from two separate .c files, you will have two discrete copies of that int, which is most likely not at all what you want.
Instead, you might consider extern int, and choose one .c file that actually defines it (i.e. just int err_code=3).
When you declared a variable as a static it has only scope within a file ie.., it can be accessed only within a file.
When you declare a static variable in a header file and include this header file in two .c file, then you are creating two different
memory for two different ".c" files
When you print err_code directly in the Main function you would see its value as 5 instead 3,
but you are calling a function printErrCode which is defined in a different file "q7a.c" for which err_code has a different memory location
in which err_code memory is still 3 and it not updated and that is why you are getting the value as 3 instead of 5.
Since two memory is created and err_code is considered as two different variables having different memory with different file scope you will not see any linking errors.
The static variables do not have external linkage which means they cannot be accessed outside the translation unit in which they are being defined. So in your case when q7.h is #include'ed in both translations units q7a.c and q7main.c ... two different copies exists in their corresponding .o files. That is why linker does not report error becuase both copies are not seen by linker while doing external symbol linkage.
While doing small research came to know that we can declare variable in Header file but in one of the source file includes that should have definition for that variable.
Instead if we define a variable in header file. in the source files where this header file included, definitions will be created which causes multiple definitions.
A static variable should be declared with in the file where we use it shouldn't be exposed to header file.
Hope I am giving right information. If I am wrong feel free to correct my statements in your comments.
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++.
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.
I have the follwoing structure and object of structure defined in the header file as below:
struct STConfigurationDetails
{
bool bAutoStart;
bool bAutoLog;
bool bAutoScan;
bool bAutoMount;
bool bAutoOpen;
bool bAutoDetectLast;
};
struct STConfigurationDetails g_objConfigurationDetails ;
In the header file it self I have both method and method body which is using g_objConfigurationDetails . This works fine when I include the header file to another cpp file and call the method. But the moment I added the header file to another cpp file I got the error:
Error 1 error LNK2005: "struct STConfigurationDetails g_objConfigurationDetails" (?g_objConfigurationDetails##3USTConfigurationDetails##A) already defined in NDSClientDlg.obj NDSConnectDlg.obj NDSClient
Error 2 fatal error LNK1169: one or more multiply defined symbols found d:\FromClearCase\Development_view\NDS_11152010\exe\Debug\NDSClient.exe 1 NDSClient
After searching few threads I found out I have to declare my object as static and it solved. But I want to know why was I getting multiple instance error while I was creating the instance only in te header file.
Is this because my Header File has a global variable and it is being included in multiple CPPs?
Adding static might solve your linking problem, but gives you a much bigger problem. That variable is no longer global and has a different value in every CPP file that uses it. You need to declare it as extern in the header file and then declare it one more time in just one CPP file as is.
When you use static it means the variable will be completely local to the current CPP file and will not be exposed to other files. That's why the linker no longer cares if there is another static variable in another file that has the same name. They are not the same variable.
If you want a truly global variable, it must be declared in exactly one CPP file and only its prototype (with extern) should be in a header file that will be shared with other CPP files. It's exactly like functions - declared in one file, prototyped for the rest. For functions, you simply don't provide a body. For variables, you use extern.
This is quite easy if you think of it carefully. The variable is defined in the header so each .cpp file that includes that header gets its own copy of the variable. Now if you don't add static all the .cpp files get the same variable with external linkage and an error occurs at compile-time.
When you add static each .cpp still has its variable unrelated to other variables from the same definition but they no longer have external linkage so the linker doesn't emit an error.
However don't forget that each variable is a separate variable that occupies memory and has overhead for construction/destruction and you will get unexpected behavior if you code expects to have only one variable shared across all .cpp files.
Global static variables have internal linkage.
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...