Declaring a struct in a header makes it global - c

There are three files:
source1.c
source2.c
header.h
The two source-files includes the header.
This is the code of the header:
struct
{
int a;
int b
} x;
What happens now is that the struct becomes global and the two source-files now shares the struct called x. Why does this happen?
I know that if you write the following code it will make two global variables. One for each of the source-files. (they don't share the globals)
int x = 0;
The last piece of code makes sense to me but i really don't understand the one with the struct..
EDIT:
Hmm everybody here think I should get linker errors. My current code is for an embedded system (nxtOSEK). I'll try to convert it to a regular C program later.
EDITEDIT:
I'm back with examples in regular C. As you can see it is not only possible with structs but also with regular variables.
source1.c
#include "header.h"
int main(void)
{
f();
x = 1;
f();
}
source2.c
#include "header.h"
void f()
{
printf("source2: %i\n", x);
}
header.h
#include <stdio.h>
int x;
Output
source2: 0
source2: 1
Note that x must not be declared for it to work or it gives a linker error like everyone here said. (I don't know why it work with the embeded system..)
It also looks like I misread Eric Postpischil's answer which looks correct.

An external declaration of an object identifier at file scope that has an initializer is a definition. The declaration int x = 0; is a definition because x is initialized.
An external declaration of an object identifier at file scope that does not have an initializer is a tentative definition. The declaration struct {…} x; is a tentative definition because x is not initialized.
Multiple definitions at link time cause an error.
Multiple tentative definitions at link time may be coalesced to a single definition, which is initialized with zero. This was traditional Unix behavior and was the default behavior with GCC prior to version 10; GCC marked tentative definitions as “common” symbols by default. With GCC version 10 and later, multiple-definition errors may result. The old behavior can be selected with the -fcommon command-line switch to GCC.
If you change int x = 0; to int x;, you will not a get a link error while using build tools that treat tentative definitions as common symbols. If you change struct {…} x; to struct {…} x = {0};, you will get a link error.

The piece of code below
struct
{
int a;
int b;
} x;
declares a variable x of type struct with no tag. This is OK for a static struct that you plan to use in a single compilation unit, but if you plan to share a struct among several .c files, you should not do it like that. Instead, you should define a tag for your struct or make a typedef for it, and declare the variable of that type separately, using the srtruct my_struct syntax.
Here is an example:
Put this struct declaration in the header:
struct a_and_b
{
int a;
int b;
};
Put this variable declaration in the .c file:
static struct a_and_b x;
Now x is no longer global: you can access it inside your .c file, but it is not visible from the outside. If you want to make it global, but avoid linker errors, add
extern struct a_and_b x;
to the header, and remove static from the declaration in the .c file.

Related

Why are function definitions implicitly external in C?

I read that the extern keyword is implicit in the context of functions, so unless you specify otherwise using the static keyword (which if I'm not mistaken is basically a completely separate concept from the static that variables employ—they just share a keyword), they are visible to all object files. This makes sense; having the declarations be implicitly external, while technically unnecessary when the declarations are in the same file as the definition, is useful because the programmer doesn't have to type extern every time they want to use a function out of its defining file, which is more often the case than not. What seems odd to me is that it is implicit for the declarations and the definition.
With a variable, I don't need to include an extern for the definition, and in fact, while I can do this without error, my compiler gives me a warning for it.
For example, I can have mylib.h:
int var = 5;
//it isn't necessary to write this as
//extern int var = 5;
//my compiler even warns against it
and test.c
#include "mylib.h"
extern int var;
I would normally assume the implicit extern for functions to be the same, that is, if I defined int func(int par) in mylib.h, there would not be an implicit extern before it, but there would be an implicit extern for any declaration of it (such as if I declared it for use in test.c).
It also doesn't make much sense from the perspective of the extern keyword being used as a way of telling the compiler to look elsewhere for the definition, when the definition would never be external of the file it is in.
I feel like I'm missing something here.
If you use int x = 10; in any header file, then you are entering into trouble, because if you include the same header file in any other file (.c or .h) that is linked with test.c then you will get an error redefinition of variable x.
You can try that for yourself.
So always keep extern int x; in a header file,
and define it int x = 10; in any .c file.
So, in this case, if you include the header file in multiple places, it is fine, because the header file only has a declaration and you can declare the same variable in multiple places without any problem.
you can try this sample program to test the error multiple definition of `global_value'
test.h
extern int global_value;
test.c
#include <stdio.h>
#include "test.h"
int global_value = 10;
int test_func()
{
printf("golbal_value = %d", global_value);
global_value = 20; // changed here, reflect in main after test_func call
}
main.c
#include <stdio.h>
#include "test.h"
int main()
{
test_func();
printf("global_value = %d\n", global_value);
return 0;
}
the above program works perfectly. to get the error bring that extern int global_value; to test.c and int global_value = 10; to test.h and compile all together gcc test.c main.c

C variable definition vs extern decleration

This seems like the sort of question that has already been covered but I can't seem to find out where.
I have come across a peculiar behaviour of gcc.
I file A I have the following definition:
struct SomeStruct {
unsigned int uiVarA;
unsigned int uiVarB;
} SomeVar;
I file B the extern decleration differs:
extern struct SomeStruct {
unsigned char filler;
unsigned int uiVarA;
unsigned int uiVarB;
} SomeVar;
In fact I can make the definition be a double and the extern decleration be an int and gcc will happily compile without so much as a warning (with -Wall and -Wextra even).
I can only conclude this must mean it is perfectly legal behaviour but how it that so?
I am aware that the linker does the job of mapping the two variables but is there no errorchecking at this stage?
Unless you include one file in the other, the compiler will not see both of your definitions.
Normally you would simply declare the struct in a header file separately and then declare variables of that type, so like:
in a.h:
struct SomeStruct {
unsigned int uiVarA;
unsigned int uiVarB;
}
In a.c you could then do: struct SomeStruct SomeVar; and in b.c extern struct SomeStruct SomeVar after including a.h. Or better yet, put the extern struct in a header file and include that in both a.c and b.c.
From the C Spec.
6.2.7 Compatible type and composite type
2 All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
So, it is not perfectly legal behavior in that the behavior is undefined. But that doesn't mean that your linker has the ability to check for it. It is syntactically correct (as long as each declaration is in different translation units).

extern with global definition of variable in c

I have the following source code which interests me.
#include <stdio.h>
extern int foo;
int foo = 32;
int main()
{
printf("%d", foo);
}
This a perfectly normal piece of code, and when I compile it with
gcc -Wall -Wextra -pedantic foo.c
I get no warnings.
And it seems weird, because a variable is defined both as external, and also global in the same file.
I'm quite sure that it's easy to the linker to find the reference for the external variable in the same file, but doesn't it look like a coding error? And if so, why doesn't the compiler warn about this?
There's nothing weird. You first made a declaration of a variable (you promised the compiler that it exist) and then you actually defined it. There's no problem in that.
Also, by default, all variables that aren't local to functions and aren't defined as static are extern.
You seem to misunderstand what extern does. extern simply makes your declaration just a declaration instead of a definition.
int i; //definition of i
extern int i; //declaration of i
It is perfectly normal to have multiple declarations of the same variable, but only one definition should be present in the whole program. Compare this with a function
void f(void); //declaration
void f(void) //definition(and redeclaration)
{
} //definition
In order to use a variable or function, you only need its declaration. Its definition may appear anywhere in the program (the linker will find it). Anywhere can be the same file, another file, or even an external library.
And it's seems weired, because a variable is defined both as external, and also global in the same file.
extern int foo;
says: it declares without defining an object of type int named foo.
int foo = 32;
it declares and defines an object of type int named foo with external linkage.
There is no contradiction and it is valid C code.
The difference is that the former is a declaration -> extern declares a variable and says it will be available somewhere around. You can have as many declarations as you want and the latter is a definition which must be there exactly once.
So there should be no warning and no error.
extern is a way to provide visibility to a variable that is defined elsewhere...
extern is like a promise...
in example.h
extern int g;// promises that this will be in the object code to anything that includes example.h
example. c
int g;

working of extern keyword

I have defined a variable in one file and declared it in another file using the extern keyword. but i have declared it with different datatype..
file1.c
char i;
main()
{
foo();
}
file2.c
void foo()
{
extern int i;
i = 130;
printf("%d", i);
}
In the above program, memory is allocated for 'i' in the main function as char datatype.
And the answer after executing should be negative(-127). But it prints 130. Whatever the value assigned to 'i' in the foo() function is printed not only 130.
"I have defined a variable in one file and declared it in another file using the extern keyword". That is just not true. char i and in main is not in any way related to int i in foo.
The variable you define as char i inside main has no linkage. It cannot be referred to by name from anywhere else in the program besides that main function. There's simply no way to do it in C. It is a local variable.
Your extern int i; declaration inside foo has absolutely no relation to that local char i; variable from main. It declares a completely different, independent variable i. The extern int i declaration in foo refers to a variable i with external linkage, i.e to a global variable i. You are still required to define that i somewhere. That i will have to be defined at file scope (since this is the only way to define a variable with external linkage). If you don't define it your program will not compile.
Entities with external linkage and entities with no linkage live in completely separate worlds. They know nothing about each other and never interact or interfere with each other.
As I said above, the code you posted in your question simply won't compile. The linker will tell you that you forgot to define the int i variable with external linkage that which you declared in used in foo. Yet, your post suggests that the code compiled successfully. This would simply mean that the code you posted is either inaccurate or incomplete. If the code is accurate, then somewhere else in your code you also defined a global variable int i. This is the global variable your foo works with, while the char i in main has absolutely nothing to do with anything.
What you have now, after your edit, is an invalid program again, albeit for a different reason. You defined a global variable char i in file1.c and then you attempted to link to it in file2.c. However, in file2.c you lied to the compiler by telling it that the global variable i has type int, while in reality it has type char.
The behavior of such program is undefined. It is illegal to use inconsistent types when declaring an entity with external linkage. If you declared a global variable of type char in one translation unit, you are not allowed to declare the same global variable with any other type in other translation units.
Some compilers might catch your error and refuse to compile the program. Most C compilers will not catch this error though. Instead the will produce a program that causes undefined behavior. This is what you got in your case. In your case that undefined behavior happened to manifest itself by printing 130 after you assigned 130 to your variable. Why you suddenly find it strange I don't know. Why you expect it to print -127 I don't know either.
Analysis — What is wrong with the code
In your code:
file1.c
int main(void)
{
char i; // Warning: unused variable
foo();
}
file2.c
void foo(void)
{
extern int i;
i = 130;
printf("%d", i);
}
The variable i in main() is wholly unrelated to the i referred to in foo(). The variable i in main() is strictly local to main() and is not passed to foo(); foo() is unable to see that i.
On Mac OS X 10.7.5 with GCC 4.7.1, the files compile separately, but they can't be linked because there is no definition for variable i.
If we move the variable i outside of main(), then the program links:
file2.h
extern void foo(void);
file1.c
#include <stdio.h>
#include "file2.h"
char i = 'A';
int main(void)
{
printf("i = %d (%c)\n", i, i);
foo();
printf("i = %d (%c)\n", i, i);
return(0);
}
file2.c
#include "file2.h"
#include <stdio.h>
void foo(void)
{
extern int i;
i = 130;
printf("i = %d (%c)\n", i, i);
}
This now links and runs, but it invokes undefined behaviour. The linker does not notice that the size of i should be sizeof(int) but is sizeof(char). The assignment in foo(), though, goes trampling out of bounds of the i that is allocated. It doesn't cause visible damage in this program, but that's pure luck.
When I run it on a little-endian machine (Intel x86/64), the output is:
i = 65 (A)
i = 130 (?)
i = -126 (?)
When I ran it on a big-endian machine (SPARC), I got a different result (which isn't very surprising; the behaviour is undefined, so any result is valid):
i = 65 (A)
i = 130 (?)
i = 0 ()
The most significant byte of the 4-byte integer was written over the only byte of the 1-byte character, hence the zero in the third line out output. Note too that it was lucky that the character was allocated an address that was a multiple of 4 bytes; that was not guaranteed and a misaligned address for an int would have caused a bus error (though experimentation suggests that it doesn't happen on SPARC even when i is forced onto an odd address; I'm not sure what is happening).
Synthesis — Correct Handling of extern
The correct way to handle this is to avoid writing external variable declarations such as extern int i; in any source file; such declarations should only appear in a header that is used everywhere the variable needs to be used.
file2.h
extern char i;
extern void foo(void);
With that change in place (and the corresponding extern int i; removed), then the output is self-consistent:
i = 65 (A)
i = -126 (?)
i = -126 (?)
Note the role of the header in keeping both file1.c and file2.c in line with each other. It ensures that the definition in file1.c matches the declaration in file2.h, and the use of file2.h in file2.c ensures that the declaration used there is correct, too. See also What are extern variables in C.
The extern declaration inside foo has absolutely no relation to that local char variable.
As far as I know, extern can be put in front of a variable declaration.
Perhaps this is a bit more confusing.
Doing that tells the compiler you want to share the variable between different .c files.
However, there has to be one .c file where the variable is declared without the extern in front of it.
Note: You're example wouldn't work anyway, as extern has no effect on local variables.
extern is a way to tell the compiler some variable you are using is implemented in another object file that you promise that you will link at link time. It is often used in library header files that involve global variables to tell the compiler that the variable is actually implemented in the library file.
Ex:
file1.c:
int thing;
int bork(int val) {
return thing += val
}
file2.c
extern int thing
int main() {
thing + 2;
}
In the case when i is declared in one file as global variable then only it has external linkage.
Linker only looks for the symbol i which will be resolved at link time ,but types are not resolved by linker so I think it's Undefined Behavior when i is of different type and defind as global variable in one file and extern declaration is done in other file.
You are LYING to the compiler about the size of i. The compiler goes by what you have told it in foo, so you are getting the integer representation. Unfortunately, it won't really work reliably, because you have also written three bytes beyond your char i;
If you add char j = 11; and then print j in main after you call foo();, you'll notice that j is not 11 any more.
Lying to compilers is a bad idea. You get found out sooner or later!
In file1.c, i is defined (and declared implicitly) globally.
char i;
main()
{
foo();
}
file2.c extern is used with a variable i, it’s only declared not defined.
extern char i;
void foo()
{
printf("%d", i);
}

Confusion between declaration and definition of a variable in C

I am new to C and I experience some confusion between the declaration and definition of a variable. Another thing I would like to know is if the following is true:
"Declaration appears many times and definition comes once."
Also:
int x;
Is this a declaration only? Since memory is allocated for x then why isn't this a definition instead of a declaration?
Simply writing int x; at either global scope or local scope, is both a declaration and definition. Typically, the declaration tells the compiler "This variable will exist, at some point, under this name, so you can use it." The definition tells the compiler to actually arrange for the variable to be created - obviously this can only happen once.
Typically the way you'll use this is by putting in a header file:
// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined
extern int bar; // Declare a variable bar
#endif
And in a single source file
#include "foo.h"
int bar; // Define bar
If you were to define bar in multiple files, you would get an error; you can't create the variable twice. But you do have to tell the compiler about it in every source file you use bar in. Hence the extern declaration.
The precise semantics are defined in §6.9.2 of the C standard and can be summarized as follows:
When a variable is declared at file scope with an initializer, it is an external definition. (§6.9.2/1)
When a variable is declared at file scope without an initializer, and without a storage-class specifier or with the static storage-class specifier, it is a tentative definition. If the translation unit (file) has one or more tentative definitions and no external definition, the compiler automatically adds a true file scope declaration at the end of the translation unit, with a zero initializer. (§6.9.2/2)
What this means is that, strictly speaking, int x; is not a definition; but it automatically creates a definition if and only if there is no other definition with an initializer, and no static definition (this third case is undefined behavior due to linkage disagreement per §6.2.2/7)
Note that extern int x; is not an external definition. It is a declaration with an extern storage class specifier. As such, extern int x; alone does not cause a definition to be created, but if you have both:
extern int x;
int x;
Then you will end up having a definition created at some point in the file.
It is also, technically speaking, legal to do this:
extern int x;
int x;
int x = 42;
In this case, the int x; in the middle is superfluous and has no effect. That said, this is poor form, as it's confusing in this case where the actual definition is.
This isn't something you see too much in C, but it works like this:
In a header file, you can have a line like this:
extern int x; //declaration
Because of the extern modifier, this tells the compiler that there is an int named x somewhere. The compiler doesn't allocate space for it - it just adds int x to the list of variables you can use. It'll only allocate space for x when it sees a line like this:
int x; //definition
You can see that because only the int x; line changes your executable, you can have as many extern int x; lines as you feel like. As long as there's only int x; line, everything will work like you want it to - having multiple declarations doesn't change a thing.
A better example comes from C++ (sorry if this is a C-only question - this applies to structs as well, but I don't know the syntax off the top of my head):
class Pineapple; //declaration
Pineapple* ptr; //this works
Pineapple pine; //this DOES NOT work
This declaration tells the compiler that there's a class called "Pineapple". It doesn't tell us anything about the class (how big it is, what its members are). We can use pointers to Pineapples now, but we can't yet have instances - we don't know what makes up a Pineapple, so we don't know how much space an instance takes up.
class Pineapple
{
public:
int ounces;
char* name;
}; //definition
Pineapple* ptr; //still works
Pineapple pine; //this works now too!
//we can even get at member variables, 'cause we know what they are now:
pine.ounces = 17;
After a definition, we know everything about the class, so we can have instances, too. And like the C example, you can have multiple declarations, but only one definition.
Hope this helps!

Resources