extern on function prototypes? - c

my_math.h
// case 1
unsigned int add_two_numbers(unsigned char a, unsigned char b);
//case 2
extern unsigned int add_two_numbers(unsigned char a, unsigned char b);
What is the difference between case 1 and case 2? I never used extern for function prototypes but looking at someone's code (who is way more experienced than I am) I see extern always used when declaring the function prototype. Can anyone point please point the difference? (or point me to a link where I can find specific information). Google says that is something related to the external linkage. Can anyone point me to an example where one would work and the other wouldn't?
I am using embedded C (KEIL), if it makes any difference.

extern is a linkage specifier for global linkage. Its counterpart is static, which specifies file-local linkage. Since global linkage is the default in C, adding extern to the declaration makes no difference for the declaration of a function. For a variable it prevents automatic memory allocation and using it is the only way to just declare a variable at global scope.
If you just google the keyword, you will find many articles e.g. this one:
geeks for geeks

I learned the following for variables years ago from an experienced programmer:
glo.h:
#ifndef EXTERN
#define EXTERN extern
#endif
...
EXTERN int gMyVar;
...
main.c:
#define EXTERN
#include "glo.h"
"glo.h" anywhere inlcuded will just declare all global variables. "glo.h" included in main.c will allocate the storage for the variables. I believe this method was common practice.

For a (non-inline) function, it doesn't make any difference, extern is implicit if no storage-class specifier is given (note, that this applies only to functions, objects are different), so it's only a matter of style what you use.
I've seen both (never use extern for functions/only use it for the declarations in the header), maybe some use extern for symmetry with object identifiers, or to make it easier to grep for external symbols.
Choose whatever you prefer and stay consistent, it doesn't make a difference.

Related

Is the visibility of a function written in C across the project files by default?

I have heard that functions in are called "extern" by default. So, according to this the scope of functions should be inside, entire the project, isn't it? I believe haven't seen this. I just like to know that is it really visible across the project files by default?
The article link: https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/
It says:
" First, Let’s consider the use of extern in functions. It turns out that when a function is declared or defined, the extern keyword is implicitly assumed. When we write.
int foo(int arg1, char arg2);
The compiler treats it as: extern int foo(int arg1, char arg2);
Since the extern keyword extends the function’s visibility to the whole program, the function can be used (called) anywhere in any of the files of the whole program, provided those files contain a declaration of the function. (With the declaration of the function in place, the compiler knows the definition of the function exists somewhere else and it goes ahead and compiles the file). So that’s all about extern and functions. "
You can find this in section "6.2.2 Linkages of identifiers" of the C11 standard draft N1570.
It says:
If the declaration of an identifier for a function has no storage-class specifier, its linkage
is determined exactly as if it were declared with the storage-class specifier extern.
The use of the extern modifier is optional for function definitions. However, many C developers use it as a matter of style, to indicate to somebody reading the source that there's no point looking for the definition of the function in the same file.
Yes all functions (if there is no other modifier) are implicitly extern. You may alter it with static modifier, which makes the function visible only for the file it is written in. Another quite common use is extern inline which makes inline functions visible for another files, not just the module they are defined in.
Yes, C defaults to global visibility for new named objects in filescope unless they're declared static.
Note that extern does not mean global visibility. It means previously declared visiblity OR (if there was no such previous declaration) global visibility.
extern optional on non-static functions (with some special meanings for the new (C>=C11) inline functions) but for filescope variable declarations it is sometimes needed to differentiate between a declaration and a tentative definition.
Examples:
void globalFunc(void);
void globalFunc(void){ }
static void fileLocalFunc(void);
void fileLocalFunc(void){ } //ok, file-local because the previous declaration was file-local
static void another_fileLocalFunc(void);
extern void another_fileLocalFunc(void){ } //extern is optional for functions
static int fileLocal_variable;
extern int fileLocal_variable; //ok, file-local, because the previous declaration was file-local
//some noncompiling stuff:
#if 0 || CONFLICTING_FUNC_DECLARATIONS0
extern void conflictingFuncDeclarations0(void);
static void conflictingFuncDeclarations0(void);
#endif
#if 0 || CONFLICTING_FUNC_DECLARATIONS1
void conflictingFuncDeclarations1(void);
static void conflictingFuncDeclarations1(void);
#endif
#if 0 || CONFLICTING_VAR_DECLARATIONS0
int conflictingVarDeclarations0;
static int conflictingVarDeclarations0;
#endif
If you're on a POSIX system, you can compile a translation unit into an object (*.o) file and then use the nm utility on it to see which names it exports (or attempts to import).

Extern makes no difference

I am defining a global variable in test2.h
#ifndef TEST2_H
#define TEST2_H
int test_var;
void use_it(void);
#endif
and defining it again in two different files, test.c
#include <stdio.h>
#include "test2.h"
int test_var;
int main() {
printf("The test_var is: %d\n", ++test_var); // prints 1
use_it(); // prints 2
}
and test2.c
#include <stdio.h>
#include "test2.h"
int test_var;
void use_it() {
printf("The test_var is: %d", ++test_var);
}
I replaced the definition of test_var with extern int test_var and got the same result. That is, in both cases both files, test.c and test2.c have access to the global variable test_var. I was under the impression that without extern, each file would have their own copy of test_var. Observation suggests that this is not the case. So when does extern actually do something?
You end up with two copies of test_var and this is undefined behavior.
(C99, 6.9p5) "If an identifier declared with external linkage is used in an expression (other than as part of the operandof 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"
In your case the linker may be nice with you and merges the two symbols but this is still not portable and is undefined behavior. If you are using the GNU linker, you can use --warn-common to get the warning (and --fatal-warnings if you want an error).
To fix your issue, put the extern specifier in the declaration of test_var in the .h file and remove one of the definition of test_var (for example the one in test.c file).
This is undefined behavior, as others have noted, but what you are seeing here is the common extension described in appendix J.5.11 of the C99 spec, where multiple external definitions in different compilation units are allowed as long as none or only one of them are initialized and the types of all of them are the same.
In this case, with the extension, the definitions will be combined into a single definition at link time.
You also appear to be confused by the fact that the extern keyword, when used at the global scope, has nothing to do with extern linkage for declarations and definitions. ALL declarations at the global scope have extern linkage unless they have a static or inline keyword. The extern keyword serves to make such a declaration just a declaration. Without the extern keyword a global variable declaration is also a definition, and that is the only effect of the extern keyword in the global scope.
If you have the same variable declared in 2 diferent files as int test_var for example:
file1.c
int test_var;
file2.c
int test_var;
both variables will have their own memory adress, so they are two diferent variables with the same name.
if you have, two variables declared in 2 diferent files declared as extern int test_var, for example:
file1.c
extern int test_var; //this is a mistake
file2.c
extern int test_var; //this is a mistake
the compiler will return an error when you try to do something with that variables because with the keyword externyou are not reserving any space for that variable, you only use that keyword to say that a variable is already defined (commonly in another file).
The point is to unsderstand that a global variable is defined once with a sentence like int test_var (when you define a variable the compiler reserve space for it) and it's declared in every other file that need access to it with extern int test_var (when you declare a variable with the extern keyword you saying the compiler that variable is already defined and you want to have access to it in the file you are declaring it).
So an example of how to use a global variable wil be:
file1.c
int test_var; //definition
void useit(void);
int main () {
test_var=7;
useit();
return 0;
}
file2.c
#include <stdio.h>
void useit (void) {
extern int test_var; //declaration
printf ("the variable value is %d",test_var);
}
To answer your question:
extern int test_var; is a declaration. This announces that "Somewhere, there should exist test_var . We don't know where that is yet, but by the time we finish compiling and linking, we will find it in exactly one place".
So there has to be exactly one definition to match. A definition serves as a declaration, and also says "Here is the storage for test_var".
Also, test_var could either have internal linkage or external linkage. The default behaviour is external linkage. If you provide more than one definition for a variable of external linkage, it is undefined behaviour.
Internal linkage is indicated by including static in the declaration. You can have as many definitions as you want of a static variable (so long as only one per file has an initializer).
Summing up, we have:
extern int test_var; // declaration, external linkage
static int test_var; // declaration, definition, internal linkage
int test_var; // declaration, definition, external linkage
Note: the last two cases are actually tentative definitions: this is a thing that C has but C++ doesn't; the way it works is that it behaves like a declaration at first; but then , for each unit, if there is no later definition then this actually serves as a definition.
So you can write in C:
int test_var;
// stuff
int test_var = 5;
If you are using gcc and possibly some other compilers, you just stumbled upon some Unix tradition. Namely that uninitialized global variables are placed in the common block where multiple definitions of the same variable are merged during linking.
gcc can be told to put uninitialized global variables into the data section with the option -fno-common. With this, the linker will report an error when there are multiple definitions of the same variable name.

understanding the extern keyword in c

#include <stdio.h>
int main()
{
extern int a;
extern int a;
int a = 10;
return 0;
}
what is the problem with this code? Since multiple declaration is allowed in c what is the problem with this code
The problem with the code is that the compiler is first informed that a is a global variable (due to the extern keyword); and then a is defined as a local 'automatic' variable. Hence there is a conflict in the defined scope of a
As an alternative to automatic variables, it is possible to define variables that are external to all functions, that is, variables that can be accessed by name by any function. (This mechanism is rather like Fortran COMMON or Pascal variables declared in the outermost block.) Because external variables are globally accessible, they can be used instead of argument lists to communicate data between functions. Furthermore, because external variables remain in existence permanently, rather than appearing and disappearing as functions are called and exited, they retain their values even after the functions that set them have returned. —The C Programming Language
An external variable must be defined, exactly once, outside of any function; this sets aside storage for it. The variable must also be declared in each function that wants to access it; this states the type of the variable. The declaration may be an explicit extern statement or may be implicit from context. ... You should note that we are using the words definition and declaration carefully when we refer to external variables in this section. Definition refers to the place where the variable is created or assigned storage; declaration refers to places where the nature of the variable is stated but no storage is allocated. —The C Programming Language
From your question I observe that you are visualizing your program something like this
#include <stdio.h>
int main()
{
extern int a; //declaration
extern int a; //declaration
int a = 10; //declaration + definiton
return 0;
}
With above understanding of extern keyword. Your question is obvious.
Let us understand use extern of keyword thoroughly.
Extern variable declaration is a promise to the compiler that there would be a definition of a global variable some place else. Read This. In other words extern keyword tell the compiler that forget about this variable at the moment and left it to linker to link it with its definition. That is extern variables are actually linked to its definition by linker. Moreover Local variables have no linkage at all. So while searching for its definition compiler found a definition without linkage. Thats the error.
As a rule of thumb just remember when you declare any variable as extern inside any function then you can only define it outside of that function.(However there is no use of it).

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;

extern declaration and function definition both in the same file

I was just browsing through gcc source files. In gcc.c, I found something like
extern int main (int, char **);
int
main (int argc, char **argv)
{
Now my doubt is extern is to tell the compiler that the particular function is not in this file but will be found somewhere else in the project. But here, definition of main is immediately after the extern declaration. What purpose is the extern declaration serving then?
It seems like, in this specific example, extern seems to be behaving like export that we use in assembly, wherin we export a particular symbol outside of the module
Any ideas?
You are misunderstanding the extern - it does not tell the compiler the definition is in another file, it simply declares that it exists without defining it. It's perfectly okay for it to be defined in the same file.
C has the concept of declaration (declaring that something exists without defining it) and definition (actually bringing it into existence). You can declare something as often as you want but can only define it once.
Because functions have external linkage by default, the extern keyword is irrelevant in this case.
Functions are implicitly extern in C. Including extern is just a visual reminder. Side note, to make a function not extern you can use the static keyword.
In a function declaration, extern simply declares that the function has external linkage, which is the default; the extern keyword is utterly useless in this context, and the effect is identical to a normal declaration/prototype without the extern keyword.
The warnings likely suggested a function prototype was missing. That's all.
The definition of the main function:
int main(int argc, char **argv) { ... }
is already a declaration is the prototyped syntax of the function main with external linkage. This means a prototyped declaration with extern just before the main definition is redundant.

Resources