Why should one use extern in a variable declared in a header file?

Asked

Viewed 35 times

1

I was searching in the background about C++ header files after I often got the error LNK2005 in the compilation of Visual Studio, and I realized that the error was that I was declaring a variable twice, in the header file and in main.cpp, and I also found several users giving the solution how to use the extern tipo nome_da_variavel; in the header file as a solution for this, and reading the answers, came to me 3 questions in the head:

1st - You really need to use the extern to declare variables of any type in a header file? If yes, why then it is not used in declaration of a class in header file, for example?

2nd - It’s good practice to use the extern in the header file? Or is there something better to use that doesn’t give the error I received above?

3rd - From what I read, the use of extern requires that I re-declare the variable also in the.cpp file, but if it is already declared in the header file, why can’t I just set its value in the . cpp?

PS: Here are the reasons why I have searched in the background about header files and generated this question here:

toast_notification. h:

#pragma once

bool dollar_value_was_changed;
bool toast_notification_was_created;

void show_toast_notification(), create_and_initialize_toast_notification(), set_toast_notification();
bool is_windows_10();

toast_notification.cpp:

#include "toast_notification.h"

#include <Windows.h>
#include <VersionHelpers.h>
#include <wintoast/wintoastlib.h>

void show_toast_notification()
{
    if (is_windows_10())
    {
        if (!toast_notification_was_created)
            create_and_initialize_toast_notification();
    }
}

bool is_windows_10()
{
    if (IsWindows10OrGreater())
        return true;
    else
    {
        MessageBox(NULL, L"Teste", L"Título da janela?", MB_OK);

        return false;
    }
}

void create_and_initialize_toast_notification()
{
    WinToastLib::WinToast::instance()->setAppName(L"Toast Dollar");
    WinToastLib::WinToast::instance()->setAppUserModelId(WinToastLib::WinToast::configureAUMI(L"Teste", L"Toast Dollar"));
    WinToastLib::WinToast::instance()->initialize();

    toast_notification_was_created = true;
}

void set_toast_notification()
{
    WinToastLib::WinToastTemplate toast_notification = WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::Text02);
    toast_notification.setTextField(L"Teste", WinToastLib::WinToastTemplate::FirstLine);
}

main.cpp:

#include "toast_notification.h"

#include <iostream>

int main()
{
    std::cout << "Hello World!\n";
    
    show_toast_notification();

    system("pause");
}

Don’t pay too much attention to the code, I ask you to turn your attention to the variable toast_notification_was_created, that in my head, as it was already stated in the header file, I could set it in the . cpp, in addition to it, the variable dollar_value_was_changed (that was not used) also generated the error that made me formulate this question

The mistakes:

1>toast_notification.obj : error LNK2005: "bool dollar_value_was_changed" (?dollar_value_was_changed@@3_NA) já definida no main.obj
1>toast_notification.obj : error LNK2005: "bool toast_notification_was_created" (?toast_notification_was_created@@3_NA) já definida no main.obj
  • Friend, in 2 I believe there are no problems, and in 3, it is worth noting that header is like a dictionary for the . cpp, it doesn’t make sense for me to add value there.

1 answer

0

yes, you need "extern", just like when you declare a function without code:

bool is_windows_10();

use extern on a variable will not define it, will only tell q it exists somewhere...

because cpp files can be compiled together or separately into objects...

and probably unless you use the compiler directly, it will compile separately.

and when linking them, if there is no "extern", each object will have its definition for that variable, after the compiler will continue processing all "include" for each cpp recursively to generate the object(.o), which will cause conflict when assembling these objects in a executable/lib/so/dll, then you should put "extern" in the header variables, and in only one of the cpp "assign" a definition to that variable using "Static" with the initial value, which will make only the object of that cpp have the definition, and the Linker gather them there is not even a duplicate!

why different objects? simple: compiling each file for an object, the compiler can take care of large projects with many files, taking advantage of the multiple cores of a modern processor.

  • 2

    This here is ruining the answer: "why different objects? simple: compiling each file for an object, the compiler can take care of large projects with many files, taking advantage of the multiple cores of a modern processor." - has no relation to the organization in objects with multiple nuclei (so much so that it was already before speaking in multiple nuclei). The fact that you can eventually compile in parallel is merely a side effect. Objects have to do with organization, in a certain way scope, and with what will actually be used when "linking" the final output.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.