Global variables initialization in C header file - c

I was wondering why declaring a global variable in a header file which is included in multiple source in C was working
#ifndef INC_MAIN_H_
#define INC_MAIN_H_
int my_var;
#endif
But assigning it a default value does not work:
#ifndef INC_MAIN_H_
#define INC_MAIN_H_
int my_var = 0;
#endif
It shows multiple compiling errors in each files where I include this main.h
multiple definition of `my_var'; app/src/testfile.o:app/inc/main.h:4: first defined here
I know declaring global variables this way is not the best practice, but I can't figure out why adding an assignation would cause compiling errors and I can't find clear answers about it.

With the build tools and switches you are using, int my_var; acts mostly like a declaration that is not a definition. Multiple declarations of an object identifier are allowed.
int my_var = 0; is a definition. There should be only one definition.
Due to the history of C use and development, int my_var; is technically a tentative definition. If there is no regular definition of my_var in the translation unit (the source file being compiled, including all the files it includes), it acts as a regular definition.
However, then when you have this in a header file that is included in multiple source files, you have multiple definitions. When there are multiple definitions of the same object identifier with external linkage, the C standard does not define the behavior.
When there are multiple regular definitions, your build tools report an error. However, they treat definitions that came from tentative definitions differently: They allow them and coalesce them into a single definition. Again, this is due to the history of how C developed and was used. Also, this behavior changed in GCC recently. Prior to GCC version 10, tentative definitions were coalesced by default, as described above. With GCC 10 and later, tentative definitions are not coalesced, and multiple definitions will result in an error. The old behavior can be requested with the switch -fcommon.
To avoid tentative definitions, you should declare the identifier in the header as extern int my_var;, which is just a declaration and not a tentative definition, and you should have exactly one source file containing int my_var = 0;, which is a regular definition and not a tentative definition.
Additional information is here, here, and here.

Related

Do variables declared in a header file give separate copies of the variables to each .c file that includes the header?

Suppose there are two source files, file_1.c and file_2.c, which include the same header file file.h. file.h has a variable int var. Once file_1.c and file_2.c include file.h, do file_1.c and file_2.c have separate copies of the variable var, or do they share the same?
Let’s start with a case that is fully defined by the C standard. If file.h contains extern int x;, it declares an identifier x to refer to some int object. This declaration is a part of each of file_1.c and file_2.c during compilation, and it is “made to refer to the same object” by linkage, per C 2018 6.2.2.
In this case, extern int x; is merely a declaration that does not define x. Some other declaration must define x. This could be done by putting int x; or int x = value; in file_1.c or file_2.c. Then the answer to your question would be that extern int x; in multiple source files would refer to the same object.
In the case you ask about, with int x; in file.h, the behavior is not fully defined by the C standard. Per C 2018 6.9.2, this is a tentative definition. If there is no regular definition of x, the C standard says the tentative definition results in x being defined as if it were initialized to zero. (In contrast, a declaration with an initializers, such as int x = 0;, is a regular definition, not a tentative definition.)
In that case, both file_1.c and file_2.c define x. So each file has its own definition. Then the C standard does not define the behavior, per 6.9 5, which says there shall be no more than one definition for such an identifier (and exactly one if it is actually used in an expression).
Since the C standard does not define the behavior, C implementations may. Until recently, GCC, Clang, and Unix tools treated tentative definitions differently from regular definitions. Multiple tentative definitions were allowed, and they were coalesced to form one definition. So, the answer to your question in this case is mixed: when int x; appears in multiple source files, it nominally refers to “different” objects in some interpretation of the C standard during compilation, but linking resolves it to the same object.
Recent versions of GCC changed this behavior. By default, tentative definitions are treated more like regular definitions, so multiple tentative definitions will result in a link error. In this case, the answer to your question is that when int x; appears in multiple source files, it refers to different objects, and this prevents the program from linking.
(This change in GCC started in version 10. The old behavior can be requested with the command-line switch -fcommon or by applying the attribute __attribute__((__common__)) to an identifier.)

Shall an variable with external linkage be defined with keyword external?

From https://www.quora.com/What-are-the-types-of-linkages-in-C-programming
External linkage, means that the variable could be defined somewhere
else outside the file you are working on, which means you can define
it inside any other translation unit rather your current one (you
will have to use the keyword extern when defining it in the other
source code).
Internal linkage, means that the variable must be defined in your
translation unit scope, which means it should either be defined in any
of the included libraries, or in the same file scope.
None linkage, points to the default functions and braces scopes, such
as defining an auto variable inside a function, this will make the
variable only accessable within that function's scope.
Note that:
Any global object is externally linked by default, you can disable that by using the keyword static.
Any constant global object is internally linked by default, you can
disable that by using the keyword extern.
Suppose a global variable is defined in file1 and I want to use it in file2.
In file1, shall the global variable be defined with keyword
extern?
The quote above seem to contradict itself:
"you will have to use the keyword extern when defining it in the other source code" seems to say it should.
"Any global object is externally linked by default" seems to say that it doesn't need to.
In file2, shall I declare global variable with keyword extern?
tldr: You should declare the variable, with extern, in a header file which is included by both file1 and file2. You should then define the variable in file1 only. To define the variable, you declare it without extern (and also without static).
You sound like you have gotten the extern keyword and the standardese term "external linkage" mixed up.
A variable with "external linkage" is accessible from any function in the program, as long as a declaration of the variable is visible to that function. In contrast, a variable with "internal linkage" is accessible from, at most, one "translation unit" (a single source file and all the files it includes), and a variable with "no linkage" is only visible within a single function. (I don't remember off the top of my head whether a static variable declared within a function is considered to have internal linkage or no linkage.)
The extern keyword, applied to a variable declaration, has two effects. First, it guarantees that that variable will be given external linkage, even if the declaration is inside a function (don't do that). Second, and much more importantly, it makes the declaration not be a definition. What that means is, if you have these two files
/* file1.c */
extern int foo;
/* file2.c */
extern int foo;
int main(void) { return foo; }
their combination is not a valid program. You will get an error from the linker, probably reading something like "undefined reference to foo".
To make this a valid program, you must remove the extern from one of the two declarations of foo. That declaration then becomes a definition, and the program will link. (Also, that declaration can then be given an initializer, if you want it to have a value other than 0 at startup.)
If you remove the extern from both of the definitions of foo, the result is, IIRC, implementation-defined. Some C compilers will merge them into a single global variable, and others will issue a link-time error. Sometimes the behavior depends on whether or not the variables have initializers.
It is OK to write
/* file1.c */
extern int foo;
/* file2.c */
extern int foo;
int foo;
This allows you to put the extern declaration in a header file that both .c files include, which reduces the risk of the declarations coming to have inconsistent types (if this happens, the program will exhibit undefined behavior).
c11 draft, 6.2.2, 4th section, states:
For an identifier declared with the storage-class specifier extern in a scope in which a
prior declaration of that identifier is visible,31) if the prior declaration specifies internal or
external linkage, the linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration. If no prior declaration is visible, or if the prior
declaration specifies no linkage, then the identifier has external linkage.
i don't think there will be any difference with or without extern keyword. some experiment also indicates that:
following 2 compiled:
extern int a;
extern int a;
int a = 20;
and
extern int a;
int a;
int a = 20;
but not this one:
extern int a;
int a = 10;
int a = 20;
however, i have some impression that once i read about the different behavior when dynamic linkage get involved in windows. I cannot find it though. it would be nice if anyone can confirm.
The text you quoted has a lot of errors. I would recommend not relying on information from that site.
(you will have to use the keyword extern when defining it in the other source code).
Not true, as file-scope definitions have external linkage unless the static keyword is used (or no specifier is used and they are re-declaring something already declared with the static keyword).
It is possible to include a redundant extern in the definition, however there must also be an initializer (otherwise it would be a declaration and not a definition).
Internal linkage, means that the variable must be defined in your translation unit scope, which means it should either be defined in any of the included libraries, or in the same file scope.
Presumably this means "included headers", not "included libraries".
Any constant global object is internally linked by default, you can disable that by using the keyword extern.
This is wrong, "global objects" have external linkage unless declared with static. The author might be mixing up C with C++ (in the latter, const global objects have internal linkage unless otherwise specified).
Suppose a global variable is defined in file1 and I want to use it in file2.
// file1.h (or any other header)
extern object_t obj;
// file1.c
#include "file1.h"
object_t obj; // or: extern object_t obj = { 1, 2, 3 };
// file2.c
#include "file1.h"

Is extern keyword in C redundant?

I have found that I could achieve the desired results without using extern (though I do agree that it gives reader some kind of an hint about the variable). In some cases using extern gave undesired results.
xyz.h
int i;
file1.c
#include "xyz.h"
....
i=10;
....
file2.c
#include "xyz.h"
main()
{
printf("i=%d\n",i);
}
Of course, it was a large project, broke it down for simple understanding. With extern keyword, I couldnt get desired results. In fact, I got linker error for the variable i with "extern" approach.
Code with "extern" approach,
file1.c
int i;
main()
{
i=10;
}
file2.c
extern int i;
foo()
{
printf("i=%d\n",i);
}
This gave linker error. I just wanted to know why it worked in the first case and also the practical case where we cannot do it without using the keyword "extern". Thanks.
Formally, your first program is invalid. Defining a variable in header file and then including this header file into multiple translation units will ultimately result in multiple definitions of the same entity with external linkage. This is a constraint violation in C.
6.9 External definitions
5 An external definition is an external declaration that is also a
definition of a function (other than an inline definition) or an
object. If an identifier declared with external linkage is used in an
expression (other than as part of the operand of a sizeof operator
whose result is an integer constant), somewhere in the entire program
there shall be exactly one external definition for the identifier;
otherwise, there shall be no more than one.
The definition of i in your first example is a tentative definition (as it has been mentioned in the comments), but it turns into a regular full fledged external definition of i at the end of each translation unit that includes the header file. So, the "tentativeness" of that definition does not change anything from the "whole program" point of view. It is not really germane to the matter at hand (aside for a little remark below).
What makes your first example to compile without error is a popular compiler extension, which is even mentioned as such in the language standard.
J.5 Common extensions
J.5.11 Multiple external definitions
1 There may be more than one
external definition for the identifier of an object, with or without
the explicit use of the keyword extern; if the definitions disagree,
or more than one is initialized, the behavior is undefined (6.9.2).
(It is quite possible that what originally led to that compiler extension in C is some implementational peculiarities of tentative definition support, but at abstract language level tentative definitions have nothing to do with this.)
Your second program is valid with regard to i (BTW, implicit int is no longer supported in C). I don't see how you could get any linker errors from it.
There are at least 2 cases where extern is meaningful and not "redundant":
For objects (not functions) at file scope, it declares the object with external linkage without providing a tentative definition; tentative definitions turn into full definitions at the end of a translation unit, and having the same identifier defined with external linkage in multiple translation units is not permitted.
At block scope (in a function), extern allows you to declare and access an object or function with external linkage without bringing the identifier into file scope (so it's not visible outside the block with the declaration). This is useful if the name could conflict with something else at file scope. For example:
static int a;
int foo(void)
{
return a;
}
int bar(void)
{
extern int a;
return a;
}
Without the extern keyword in bar, int a; would yield a local variable (automatic storage).

C - Scope of C Functions

I apologize if this is a beginner's question, but after working in C for a bit, I finally would like a bit of clarification on exactly what kind of files/functions are available to a function.
I understand we can explicitly include other files with the #include macro like so:
#include bar.c
But what about files that are in the same directory? Let's say we have the following file structure:
src-
|
a.c
b.c
And let's say a.c has the function "foo()" and b.c has "bar()"
Would I be able to call bar() within a.c even without explicitly including b.c in the header file?
And what about in sub-directories such as the following:
src-
|
a.c
|
someFolder-
|
b.c
Would I still be able to access bar() in a.c?
Basically, how exactly is the scope of functions (without including them in headers) defined?
You are confusing scope with linkage.
The term scope descibes if an identifier is visible to the compiler in a given context. The broadest scope known to the C language is file scope which means that the identifier is visible from the point it is declared to the end of the translation unit after preprocessing. You can make any identifier visible/known by declaring it, but making an identifier visible does not mean that refering to the identifier refers to the thing it refers to in another file.
The term linkage describes how two identifiers refer to the same thing. There are three levels of linkage: with no linkage, each identifier with the name refers to a different thing. With internal linkage, each identifier within the same translation unit refers to the same thing. With external linkage, each identifier in the whol program refers to the same thing. For two identifiers in two translation units to refer to the same thing, you need to declare both of them to have external linkage.
This is independent of how the declaration is obtained. There is no difference in writing int foo() in a common header file to writing the same line in both source files. In either case, all identifiers refer to the same foo() as functions have external linkage unless explicitly declared to have internal linkage with the static type specifier.
It is also independent of how your source code is laid out. As long as all translation units are linked into the same binary, you can call all functions with external linkage in each translation unit.
Depends on whether you are linking these into one binary or not.
If linking - then yes, functions can be called with implicit declaration.
Common pattern in this case is making a header(s) file with all declarations, including *.c files is usually not preferred, since #include is just textual inclusion of file contents
#include (a preprocessor directive, not a macro, BTW) has a configurable list of directories it searches.
If you use the #include "something.h" form (as compared to the angle bracket form for including system headers), the first directory in the list is the directory of the including file.
Although #include does a simple textual inclusion so it is technically possible to include any text file, c files are almost never included.
In C, you usually compile c files separately into object files and link them together, and what you do include is header files which consist of declarations, which represent interfaces of the other object files which your current compilation unit otherwise wouldn't see.
Check out http://www.cs.bu.edu/teaching/c/separate-compilation/ or another article on that topic.
The forward slash "/" should work in this case.
If you can include foo.h without problem, this means the directory (say, C:\DIRFOO) is predefined in the "include" directive of the compiler. So, another file (say bar.h) in a sub directory (say, C:\DIRFOO\DIRBAR) can be included via #include <DIRBAR/bar.h>.

variable redefinition, embedded c

I'm working on an embedded c project and am having issues with global variable redefinition.
I've split up the function declarations and definitions into a handful of .h and .c files. Many of these functions need access to global variables, which are defined in global_vars.h. Therefore, at the beginning of the header files, inside the #ifndef, #define section, "global_vars.h". If I don't, as you might imagine I get a bunch of undefined variable errors.
However, even though global_vars.h has the #ifndef _GLOBAL_VARS_H_ #define... #endif, I get redefinition errors for all the global variables. My guess is that when the linker tries link the various object files, it sees the redefinition due to the #include "global_vars.h" in all the "blah_blah.h" files. It was my understanding, though, that the #ifndef... takes care of this issue.
Is there something I'm overlooking?
Thanks in advance
The linker never sees anything in the global_vars.h file, ever, unless -- bad news! -- some of the globals are actually defined in that file. global_vars.h should hold only declarations of those global variables, never (well, almost never) their definitions.
In global_vars.h, you should have declarations like:
extern int some_global;
You are not allowed to have:
int some_global;
If you have definitions in global_vars.h then, yes, they'll be multiply defined at link time because each of the .c files that #includes global_vars.h will have its own definition of each defined variable.
All of the definitions of the extern globals must be in some .c file, for sure. Usually it doesn't matter which .c file. Often all of the global-variable definitions are in a file called (surprise!) global_vars.c.
So make sure there aren't any global-variable definitions in global_vars.h and you'll be in good shape.
Is not a good idea to define globals in an H file. Better if you do that in a C or C++ file and you include and H file in other modules with those globals as externals.
Like this>>>
My module c 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 H file globals.h
// this is to include only once
#ifndef MYH
#define MYH
extern unsigned short int AGLOBAL; // no value in here!
#endif
Other module c file
#include globals.h
char SomeOtherFunc(void)
{
AGLOBAL+=10; // ok cause its defined by globals.h
// do more....
}
So let me start with saying that extern keyword applies to C variables (data objects) and C functions. Basically extern keyword extends the visibility of the C variables and C functions. Probably that’s is the reason why it was named as extern.
Use of extern with C functions. By default, the declaration and definition of a C function have “extern” prepended with them. It means even though we don’t use extern with the declaration/definition of C functions, it is present there.
For example, when we write.
int foo(int arg1, char arg2);
There’s an extern present in the beginning which is hidden and the compiler treats it as below.
extern int foo(int arg1, char arg2);
Same is the case with the definition of a C function (Definition of a C function means writing the body of the function). Therefore whenever we define a C function, an extern is present there in the beginning of the function definition. Since the declaration can be done any number of times and definition can be done only once, we can notice that declaration of a function can be added in several C/H files or in a single C/H file several times. But we notice the actual definition of the function only once (i.e. in one file only). And as the extern extends the visibility to the whole program, the functions can be used (called) anywhere in any of the files of the whole program provided the declaration of the function is known. (By knowing the declaration of the function, C compiler knows that the definition of the function exists and it goes ahead to compile the program).
So that’s all about extern with C functions.
Declaration can be done any number of times but definition only once.
“extern” keyword is used to extend the visibility of variables/functions().
Since functions are visible through out the program by default. The use of extern is not needed in function declaration/definition. Its use is redundant.
When extern is used with a variable, it’s only declared not defined.
As an exception, when an extern variable is declared with initialization, it is taken as definition of the variable as well.

Resources