Extern in C++

The word “extern” in C++ is a specifier. Its use in C++ is explained in this article for variables and functions. First, the meanings of declaration and definition in C++ are given. Consider the following lines of code:
    int it;

    char fn(int itg, char ch);

    it = 5;

    char fn(int itg, char ch) {
        char var = 'o';
        if (itg == 1 && ch == 'a')
            var = 'z';
        return var;
    }

The first line is a variable declaration. The second line would have been a function signature if it had never ended with a semicolon followed by a function body. This second line ending with a semicolon is a function prototype. It is also a function declaration. The third line assigns value to the integer variable: this is a variable initialization but can still roughly be seen as a variable definition. The rest of the code is a function definition. It begins with the function signature, followed by the function body.

There is a nuance in C++ when it concerns declaration and definition. The following statement is a variable declaration:

    int it = 5;

A complete variable declaration like this, where the variable is introduced and then assigned a value, is still a variable declaration. So, a variable declaration can just be introducing the variable alone or the introduction with the definition.

The following code (copied from above) is a function declaration:

    char fn(int itg, char ch) {
        char var = 'o';
        if (itg == 1 && ch == 'a')
            var = 'z';
        return var;
    }

A complete function declaration like this, where its signature introduces the function and is then followed by the function body, is still a function declaration. So, a function declaration can just be the function prototype alone, or it can be the function signature together with the function body.

So, a declaration can be with or without a definition. A definition is like a sub-part of a declaration. With the variable, assigning a value for the first time is actually initialization and not really defined. When a variable is declared for the first time without initialization, its location in memory is already provided, but it is empty. Fitting in a value at the location is an initialization, which is completing the definition.

Traditionally, a simple C++ application has three files. It has a main file that can be called the first file. It has a second file and a header file. The use of the extern specifier can reduce the number of files to two (from three). This article explains the use of the extern specifier with variables and functions to avoid the header file. Note: in C++ vocabulary, such two files are called translation units.

Article Content

Header File without extern

Traditionally, a simple C++ application has three files: the main file with the main() function that can be called the first file, a second file, and a header file. The header file should have the declarations of variables and functions without their definitions. The definitions of the header declarations should be in the second file. At the top of the first file, there has to be,

    #include "head.hh"

Where head.hh is the name of the header file, and it resides in the user-home directory. The include directive does not end with a semicolon. In this situation, the variable declarations without definitions, and the function prototypes without function definitions in the header file, should not be preceded by the extern specifier. And the application should work.

Illustration
The above variable and function are used for illustration here.

Type the following code in a text editor and save it in the user-home directory, with the name, head.hh :

    int it = 5;
    char fn(int itg, char ch);

There are just two statements in the header. Next type the following in an untitled document of the text editor and save in the user-home directory, with the name, second.cpp :

    char fn(int itg, char ch) {
        char var = 'o';
        if (itg == 1 && ch == 'a')
            var = 'z';
        return var;
    }

And next, type the following code in another untitled document of the text editor and save it in the user-home directory, with the name, first.CPP :

    #include "head.hh"
    #include
    using namespace std;

    int main()
    {
        cout << it << endl;
        cout << fn(1, 'a') << endl;
   
        return 0;
    }

Compile the application with the following terminal command:

    g++ first.cpp second.cpp -o complete.exe

Execute the application with,

    ./complete.exe

The output is:

    5
    z

Unfortunately, the header file does not allow a simple declaration of a variable (e.g., it) without initialization. However, this problem can be resolved as shown below.

extern without Header File

The header file can be eliminated if the extern specifier is used appropriately. There will be a declaration for the variable and function in this situation, each without definition in the first (main) file. Each will be preceded by an extern.

Illustration
Type the following code in a text editor and save it in the user-home directory, with the name, first.cpp :

    #include
    using namespace std;

    extern int it;

    extern char fn(int itg, char ch);

    int main()
    {
        cout << it << endl;
        cout << fn(1, 'a') << endl;

        return 0;
    }

Next, type the following in an untitled document of the text editor and save in the user-home directory with the name, second.cpp :

    int it = 5;

    char fn(int itg, char ch) {
        char var = 'o';
        if (itg == 1 && ch == 'a')
            var = 'z';
        return var;
    }

The definition of the variable and the function have taken place in the second file. In the first file here, they have been declared without definition. No header has been included in this new application. Only two files are involved. Note that the variable has been declared completely in the second file but without the word extern. Even the function, too, has been declared completely without the word extern. However, the word "extern", must precede the partial declarations in the first file.

Compile the application with the following terminal command:

    g++ first.cpp second.cpp -o complete.exe

Run the application with,

    ./complete.exe

The output is:

    5
    z

Same as before, but without any header file.

So, the extern specifier links declarations between two files. One file should do declaration without definition and with extern. The other file should do a definition, which would be a complete declaration, but without an extern.

Header File and extern

The above application had the problem that the variable had to be declared completely in the header file. In order to have the declaration of a variable in a header file without the definition, the variable has to be preceded by an extern. So, if there is,

    extern int it;

in the header file, there would be

    int it = 5;

in the second file, and there would still be

    #include "head.hh"

At the top of the first file (main file).

Constant and extern

Under normal circumstances, a constant must be initialized. For example,

    const char ch = 'e';

is allowed and

    const char ch;

Is not allowed.

However, with the extern specifier, a constant can be declared without initialization in the first and second files. So, if in the first file, there is

    extern const char ch;

in the second file, there will be

    char ch = 'e';

Without const in the second file. ch in both files is the same entity.

Replace the first.cpp file with the following content and save:

    #include
    using namespace std;

    extern const char ch;

    int main()
    {
        cout << ch << endl;

        return 0;
    }

Replace the second.cpp file with the following content and save:

    char ch = 'e';

Compile the application with the following terminal command:

    g++ first.cpp second.cpp -o complete.exe

Run the application with,

    ./complete.exe

The output should be, e.

extern and static

Storage class specifiers in C++ are static, thread_local, extern, mutable. Not more than one of these can be used in a given declaration. However, in a few cases, thread_local and static may appear in front of an entity declaration, or thread_local and extern may appear in front of an entity declaration. So, extern and static can never be present as specifiers for a declaration.

Conclusion

The extern specifier links two declarations of the same entity, which are in two different files. The declaration having the extern specifier should not be initialized or defined. The declaration in the other file that does not have the extern specifier should be initialized or defined. This scheme applies to variables and functions. It eliminates the need for a header file for the variables and functions of interest. It allows a constant to be declared without initialization in one file and in the other file. If the programmer wants a header file, then in order to have a variable in the header file, without initialization, the programmer has to use extern for the variable in the header file.



from https://ift.tt/3mSh90T

Post a Comment

0 Comments