Understanding how extern works - c

The way I understand extern is that we are able to declare a variable anywhere in a program and use it, but we can just define it once. I am getting an error in the following program.
hello.c
#include <stdio.h>
#include "function.h"
extern int c;
int main()
{
int c;
c=10;
printf("%d\n",c);
printExternValue();
return 0;
}
function .h
void printExternValue();
function .c
#include "function.h"
#include "stdio.h"
extern int c;
void printExternValue()
{
printf("%d\n",c);
}
I expect this program to print out:
10
10
But it's not doing so since it's giving an error. I re-declared the variable c in the function.c file with the intention of using the value that is stored in the so called external storage.
Error: function.c:(.text+0x6): undefined reference to `c'
I am currently reading a PDF file from tutorialspoints which I think to be very redundant since the intention of creating a variable with the aggregate extern is useless. The right way this should be done is that they define the variables outside the function is that right?
#include <stdio.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main ()
{
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c);
f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
}

Variable declread as
extern int c;
is an external declaration that potentially requires an external definiton. "External" in this case means "located outside of any function". Your c declared locally in main() does not fullfill that role.
Since you are using that externally declared variable c in your code you have to define it and define it only once.
You need
int c;
or
int c = 0;
or
extern int c = 0;
it one of your implementation files, at file scope. All of these are definitions. Any of them will define your variable.

Define your variable once in one of your files (to reserve space),
int c = 0;
Declare your variable references everywhere else (in all of your other files) (to reference said space),
extern int c;
But that could be confusing, so name them indicative of the 'global' use,
int glob_a, glob_b;
int glob_c;
float glob_f;
And declare your variable references everywhere else,
extern int glob_a, glob_b;
extern int glob_c;
extern float glob_f;
But you really want to avoid littering you namespace, so when you have a collection of globals, declare a struct that contains them (in a header file probably called globals.h),
typedef struct globals_struct {
int a, b;
int c;
float f;
} globals_t;
And once (in your file main.c that declares main()), you define the struct,
#include globals.h
globals_t globs;
And everywhere else, reference the space,
#include globals.h
extern globals_t globs;
Often, you will see a stanza such as this, where MAIN is only declared in one file,
#ifndef MAIN
extern globals_t globs;
#else
globals_t globs;
#endif
Use your globals,
int my_a = globs.a;
int my_b = globs.b;
int my_f = globs.f;
Notice how you have avoided needless namespace pollution?
Because extern just tells the compiler (actually the linker) that a variable is being defined elsewhere and needs to be linked against.

Related

why volatile can repeat declare?

#include <stdio.h>
volatile int isInit_STD;
volatile int isInit_STD;
int main() {
printf("v-%d-addr%x\n",isInit_STD,&isInit_STD);
isInit_STD = 1;
printf("v-%d-addr%x\n",isInit_STD,&isInit_STD);
return 0;
}
and the result is:
v-0-addr387fd040
v-1-addr387fd040
why volatile can repeat declare?
It turns out they are all the same, the same address.
If one of them deletes the 'volatile', that can't be compiled success.
I want to know the reason, looking forward to your reply.
The C standard says that (C17 6.7/4)
All declarations in the same scope that refer to the same object or function shall specify compatible types.
That means that as long as you use the same name, same type and same type qualifiers (volatile etc), you can declare the variable as many times as you like, and it will all refer to the same object.
And the opposite: if you use different types or qualifiers, but give the variable the same name, it is a constraint violation and the compiler must issue a diagnostic message.
Apart from what standard C allows, common sense states that we should avoid having multiple declarations of the same variable when possible. Good program design practices also state that we should avoid declaring objects at file scope, or if that's not possible, avoid using external linkage ("globals") and instead enforce interal linkage by declaring the variable static.
I want to know the reason
You can repeat a declaration of anything as many times as you want, as long as the declarations are "the same". It's not specific to volatile, just there has to be no conflict. All declarations refer to the same thing.
The following is an actual whole .c file:
// 3 declarations of function main.
int main();
int main();
int main();
// 3 declarations of struct A type.
struct A;
struct A;
struct A;
// 3 declarations of variable a
extern volatile int a;
extern volatile int a;
extern volatile int a;
// 3 declarations of variable b
int b;
int b;
int b;
// 3 declarations of variable c
volatile int c;
volatile int c;
volatile int c;
// example with conflicts:
int d;
// volatile int d; // error - conflict with above, d is not volatile
// static int d; // error - conflict with above, d is not static
extern int d; // Fine! Stuff declared at file scope is implicitly extern.

defining extern variable inside of the scope and outside of the scope

I defined extern a in the scope and outside of the scope
a.c
int a;
void foo(void)
{
a = 3;
}
b.c
extern int a = 10; /*same as "extern a; int a = 10?" */
void foo(void);
int main(void)
{
foo();
printf("%d", a);
}
Is this code well-defined?
This causes undefined behaviour in Standard C due to multiple definition of a.
There is a common extension for implementations to allow multiple definition so long as at most one is initialized.
For more detail see: Is having global variables in common blocks an undefined behaviour?
extern int a = 10; is the same as int a = 10; which is the same as extern int a; int a = 10; . Variable definitions have external linkage unless specified as static (or the identifier already declared as static in the same scope).
extern int a = 10; is the same as int a = 10;
If you have both the code will not link as there will be multiple definitions of the static storage variable a in your project.

Confusion about the extern keyword and multiple source files

I am trying to fully understand how extern works, so I created 3 files, two of them are source files and the last is a header file. This is what is contained in each of them:
testingfile1.c
#include <stdio.h>
#include "testingheader.h"
int main() {
change();
int my_extern;
printf("\n%d", my_extern);
return 0;
}
testingfile2.c:
#include <stdio.h>
#include "testingheader.h"
void change() {
int my_extern;
my_extern = 15;
printf("%d", my_extern);
}
testingheader.h:
#if !defined(TESTINGHEADER_H)
#define TESTINGHEADER_H
#include <stdio.h>
extern int my_extern;
void change();
#endif
The output of this program is: 15 0. However, I thought that since my_extern is an extern int, if you were to change to the value in one source file, it's value would be changed in all of the other source files. Is this not how extern works, or am I doing something wrong in the code itself?
In both cases remove int my_extern; where you have it, because those become local variables which happen to have the same name my_extern.
extern int my_extern; just means there's an int called my_extern "out there somewhere". So you'd have to declare int my_extern somewhere at file scope, for example like this:
int my_extern = 0;
void change() {
my_extern = 15;
printf("%d", my_extern);
}
In testingfile2.c, the my_extern variable is local to the function and you are not seeing the global my_extern that the extern command is referencing. Of course, you don't have a global my_extern, so that is another problem. You would get a linker error if you actually tried to reference the global my_extern that the extern command is referencing.
The issue is you're re-declaring int my_extern; inside your functions. Therefore, C treats that as a separate variable from the global my_extern.
The statement extern int my_extern; is a declaration that a global int called my_extern will be declared somewhere. You haven't done that. Instead, you've created local my_extern variables.

variable between files [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I share variables between different .c files?
If I have two source files, and one header: file1.c, file2.c, and header.h, and:
--header.h--
int i;
--file1.c--
#include <header.h>
i = 10;
int main() {
func();
return 0;
}
--file2.c--
#include <header.h>
void func() {
printf("i = %d\n", i);
return;
}
I get the warning that i defaults to an int. What could I do if I want to have i as a float for instance?
Make it
extern int i;
in the header and
int i = 10;
in file1.c.
The warning means that for the (incomplete) declaration i = 10; in file1.c, the "implicit int" rule is applied, in particular, that line is interpreted as a declaration (since an assignment cannot appear outside function scope).
You have a couple of errors in your code. The first is that you define the variable i in the header file, which means that it will be defined in all source files that include the header. Instead you should declare the variable as extern:
extern int i;
The other problem is that you can't just assign to variables in the global scope in file1.c. Instead it's there that you should define the variable:
int i = 10;
Declare it as extern in the header (this means memory for it is reserved somewhere else):
/* header.h */
extern int i;
Then define it in only one .c file, i.e. actually reserve memory for it:
/* file1.c */
int i = <initial value>;
In the header use
extern int i;
in either file1.c or file2.c have
int i = 20;
If you want float just change int to float
In 99.9% of all cases it is bad program design to share non-constant, global variables between files. There are very few cases when you actually need to do this: they are so rare that I cannot come up with any valid cases. Declarations of hardware registers perhaps.
In most of the cases, you should either use (possibly inlined) setter/getter functions ("public"), static variables at file scope ("private"), or incomplete type implementations ("private") instead.
In those few rare cases when you need to share a variable between files, do like this:
// file.h
extern int my_var;
// file.c
#include "file.h"
int my_var = something;
// main.c
#include "file.h"
use(my_var);
Never put any form of variable definition in a h-file.

How to access a structure declared in other file using extern keyword in 'c' language

I have 3 files . In one file I declared a structure and in another file which has the main, I am trying to access that structure using extern key word --------
//a.c---
include<stdio.h>
extern struct k ;
extern int c;
int main()
{
extern int a,b;
fun1();
fun2();
c=10;
printf("%d\n",c);
struct k j;
j.id=89;
j.m=43;
printf("\n%d\t%f",j.id,j.m);
}
//1.c
#include<stdio.h>
struct k
{
int id;
float m;
}j;
int c;
void fun1()
{
int a=0,b=5;
printf("tis is fun1");
printf("\n%d%d\n",a,b);
}
//2.c--
#include<stdio.h>
struct k
{
int id;
float m;
}j;
void fun2()
{
int a=10,b=4;
printf("this is fun2()");
printf("\n%d%d\n",a,b);
}
I compiled this code by using cc a.c 1.c 2.c
but I am getting error as storage size of ‘j’ isn’t known
//a.h---
#include<stdio.h>
#include "1.h"//cannot know its there without including it first.
#include "2.h"
extern struct k;// don't really need to do this and is wrong.
extern int c;
//a.c
int main()
{
extern int a,b;//externs i believe should be in the h file?
fun1();
fun2();
c=10;
printf("%d\n",c);
struct k *ptr = malloc(sizeof(struct k));//Define our pointer to the struct and make use of malloc.
//now we can point to the struct, update it and even retrieve.
ptr->id = 89;
ptr->m = 43;
printf("\n%d\t%f" ptr->id,ptr->m);
}
//1.h
#include<stdio.h>
typeof struct k
{
int id;
float m;
}j;
//1.c
int c;
void fun1()
{
int a=0,b=5;
printf("tis is fun1");
printf("\n%d%d\n",a,b);
}
//2.h--
#include<stdio.h>
struct k
{
int id;
float m;
}j;
//2.c
void fun2()
{
int a=10,b=4;
printf("this is fun2()");
printf("\n%d%d\n",a,b);
}
I have edited your code in places so it should see the struct and point to it. Each C file should know have an header h file. When the a.h belonging to your main includes files not only it can see them but should be able to access them. This means it should also know what K is J is alias of K if I remember correctly.
I should know update the struct and retrieve data from it via pointer. If this still doesn't work please post your compiling error and copy n paste the line its crying about.
You have no definition for struct k visible from a.c. Put the definition in a header file and include it from all three source files.
struct k is a description of how to build an object. It is not an object. extern operates on objects.
Usually struct blocks are placed in a header, or .h file.
j is an object of type k. It should be declared extern in either 1.c or 2.c.
Functions which are used among multiple files, like variables, should be declared before use.
Putting it all together, you might want
//a.c---
#include <stdio.h>
#include "k.h" /* contains definition of struct k */
extern int c;
extern k j;
extern void fun1();
extern void fun2();
int main()
{
extern int a,b;
fun1();
fun2();
c=10;
printf("%d\n",c);
j.id=89;
j.m=43;
printf("\n%d\t%f",j.id,j.m);
}
Some of your concepts are wrong. Please check this link.
To access a variable as extern you have to first define it, which you have not done in your case.
The extern modifier changes the linkage of the variable that you are declaring or defining. In C, only variable names can have linkage - not types, like struct k.
If you wish to access the internals of a struct type, it must be fully defined in the same source file. The usual way to accomplish this for types that are shared between source files is to place the definition of the struct into a header file, which is included with #include into each source file.

Resources