ChatGPT解决这个技术问题 Extra ChatGPT

How to correctly use the extern keyword in C

c

My question is about when a function should be referenced with the extern keyword in C.

I am failing to see when this should be used in practice. As I am writing a program all of the functions that I use are made available through the header files I have included. So why would it be useful to extern to get access to something that was not exposed in the header file?

I could be thinking about how extern works incorrectly, and if so please correct me.

Also.. Should you extern something when it is the default declaration without the keyword in a header file?


N
Neuron

extern changes the linkage. With the keyword, the function / variable is assumed to be available somewhere else and the resolving is deferred to the linker.

There's a difference between extern on functions and on variables.

For variables it doesn't instantiate the variable itself, i.e. doesn't allocate any memory. This needs to be done somewhere else. Thus it's important if you want to import the variable from somewhere else.

For functions, this only tells the compiler that linkage is extern. As this is the default (you use the keyword static to indicate that a function is not bound using extern linkage) you don't need to use it explicitly.


then why the same extern thing is there in Git:a very popular and modern software check it: github.com/git/git/blob/master/strbuf.h
K&R do not note that it is default to declare function as "extern", however this answer solve my confusion!
@rsjethani I think it is to make the document more strict and format.
Maybe a dumb question, but how does this compare to forward declaration?
N
Neuron

extern tells the compiler that this data is defined somewhere and will be connected with the linker.

With the help of the responses here and talking to a few friends here is the practical example of a use of extern.

Example 1 - to show a pitfall:

stdio.h:

int errno;

myCFile1.c:

#include <stdio.h>

// Code using errno...

myCFile2.c:

#include <stdio.h>

// Code using errno...

If myCFile1.o and myCFile2.o are linked, each of the c files have separate copies of errno. This is a problem as the same errno is supposed to be available in all linked files.

Example 2 - The fix.

stdio.h:

extern int errno;

stdio.c:

int errno;

myCFile1.c:

#include <stdio.h>

// Code using errno...

myCFile2.c:

#include <stdio.h>

// Code using errno...

Now if both myCFile1.o and MyCFile2.o are linked by the linker they will both point to the same errno. Thus, solving the implementation with extern.


The problem isn't that the myCFile1 and myCFile2 modules have a separate copy of errno, it's that they are both exposing a symbol called "errno". When the linker sees this, it doesn't know which "errno" to pick, so it will bail out with an error message.
what does "linked by the linker" actually means ? everybody uses this term, I don't find any definition :(
@MarcelFalliere Wiki ~ Compiler compiles each source file on its own and creates an object file for each source file. Linker links these object files to 1 executable.
Doesn't an include guard protect against this exact thing?
@obskyr no, include guards will not protect against this. Include guards just prevent the same header file from being included multiple times in a single source file. It does not prevent that header from showing up in multiple source files. So you'd still have the problem that multiple sources defined the same variable.
q
qris

It has already been stated that the extern keyword is redundant for functions.

As for variables shared across compilation units, you should declare them in a header file with the extern keyword, then define them in a single source file, without the extern keyword. The single source file should be the one sharing the header file's name, for best practice.


@aib "redundant for functions",check my comment in bluebrother's answer.
What if you don't want to expose any of the functions in the header file? Wouldn't it be better to declare the the variable in one C file and access it by extern in another; let the linker resolve the problem and hide the rest of the header.
N
Neuron

Many years later, I discover this question. After reading every answer and comment, I thought I could clarify a few details... This could be useful for people who get here through Google search.

The question is specifically about using extern functions, so I will ignore the use of extern with global variables.

Let's define 3 function prototypes:

// --------------------------------------
// Filename: "my_project.H"
extern int function_1(void);
static int function_2(void);
       int function_3(void);

The header file can be used by the main source code as follows:

// --------------------------------------
// Filename: "my_project.C"
#include "my_project.H"

void main(void) {
    int v1 = function_1();
    int v2 = function_2();
    int v3 = function_3();
}

int function_2(void) return 1234;

In order to compile and link, we must define function_2 in the same source code file where we call that function. The two other functions could be defined in different source code *.C or they may be located in any binary file (*.OBJ, *.LIB, *.DLL), for which we may not have the source code.

Let's include again the header my_project.H in a different *.C file to understand better the difference. In the same project, we add the following file:

// --------------------------------------
// Filename: "my_big_project_splitted.C"
#include "my_project.H"

void old_main_test(void){
    int v1 = function_1();
    int v2 = function_2();
    int v3 = function_3();
}

int function_2(void) return 5678;

int function_1(void) return 12;

int function_3(void) return 34;

Important features to notice:

When a function is defined as static in a header file, the compiler/linker must find an instance of a function with that name in each module which uses that include file.

A function which is part of the C library can be replaced in only one module by redefining a prototype with static only in that module. For example, replace any call to malloc and free to add memory leak detection feature.

The specifier extern is not really needed for functions. When static is not found, a function is always assumed to be extern.

However, extern is not the default for variables. Normally, any header file that defines variables to be visible across many modules needs to use extern. The only exception would be if a header file is guaranteed to be included from one and only one module. Many project managers would then require that such variable be placed at the beginning of the module, not inside any header file. Some large projects, such as the video game emulator "Mame" even require that such variables appears only above the first function using them.


So why exactly does a static function need a definition versus the extern ones? (I know this is 2 years late, but this is actually really helpful for understanding)
The definition is needed if you call the function at line 100 and instanciate it at line 500. Line 100 would declare undefined prototype. So, you add the prototype near the top.
N
Neuron

In C, extern is implied for function prototypes, as a prototype declares a function which is defined somewhere else. In other words, a function prototype has external linkage by default; using extern is fine, but is redundant.

(If static linkage is required, the function must be declared as static both in its prototype and function header, and these should normally both be in the same .c file).


q
qris

A very good article that I came about the extern keyword, along with the examples: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

Though I do not agree that using extern in function declarations is redundant. This is supposed to be a compiler setting. So I recommend using the extern in the function declarations when it is needed.


I've read the geeksforgeeks.org article before I came here, but found it quite poorly written. Apart from the grammatical and syntax shortcomings, it uses a lot of words to make the same point several times and then skims critical information. For instance, in Example 4, suddenly 'somefile.h' is included, but nothing is said about it other than: "Supposing that somefile.h has the definition of var". Well, the information that we're "supposing" just happens to be the information I'm looking for. Unfortunately, none the answers on this page are much better.
C
Chris Lutz

If each file in your program is first compiled to an object file, then the object files are linked together, you need extern. It tells the compiler "This function exists, but the code for it is somewhere else. Don't panic."


Um, that's how translation is normally done: source files compile to object files, and are then linked. When would you not need extern in that case? Nor would you use #include to get functions, but rather function prototypes. I don't understand what you're talking about.
I seem to be having this problem lately of misreading things. Sorry about that. When I was new to C, I would #include "file.c" to just include the functions in one file directly into the other file. Then I figured out how to use 'extern'. I thought he was making the same mistake I was.
C
Christoph

All declarations of functions and variables in header files should be extern.

Exceptions to this rule are inline functions defined in the header and variables which - although defined in the header - will have to be local to the translation unit (the source file the header gets included into): these should be static.

In source files, extern shouldn't be used for functions and variables defined in the file. Just prefix local definitions with static and do nothing for shared definitions - they'll be external symbols by default.

The only reason to use extern at all in a source file is to declare functions and variables which are defined in other source files and for which no header file is provided.

Declaring function prototypes extern is actually unnecessary. Some people dislike it because it will just waste space and function declarations already have a tendency to overflow line limits. Others like it because this way, functions and variables can be treated the same way.


Can you give a reason to why "All declarations of functions and variables in header files should be extern."? It look to me from the other responses that they are extern by default.
@Lane: extern is optional for function declarations, but I like to treat variables and functions the same way - at least that's the most reasonable thing I could come up with, as I don't exactly remember why I started doing this ;)
Isn't it a better idea to always include global variables into the C file so they do not get seen by other random C files that include the header. And to always use extern on every global except the initialized true sink as a matter of clarity; if it is prefixed extern then it is defined elsewhere.
E
Eduard - Gabriel Munteanu

Functions actually defined in other source files should only be declared in headers. In this case, you should use extern when declaring the prototype in a header.

Most of the time, your functions will be one of the following (more like a best practice):

static (normal functions that aren't visible outside that .c file)

static inline (inlines from .c or .h files)

extern (declaration in headers of the next kind (see below))

[no keyword whatsoever] (normal functions meant to be accessed using extern declarations)


Why would you extern when declaring the prototype if this is the default?
@Lane: Might be a bit biased, but every sane project I've worked on uses the following convention: in headers, declare prototypes only for external functions (hence extern). In .c files, plain prototypes can be used to obviate the need for specific ordering, but they shouldn't be placed in headers.
O
Otávio Décio

When you have that function defined on a different dll or lib, so that the compiler defers to the linker to find it. Typical case is when you are calling functions from the OS API.