0

I was researching in depth about C ++ header files after I often received the LNK2005 error in the Visual Studio compilation, and 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 type variable_name; in the header file as a solution to this, and reading the answers, 3 questions came to my mind:

1st - Do you really need to use extern to declare variables of any type in a header file? If so, why is it not used in declaring a class in a header file, for example?

2nd - Is it a good practice to use extern in the header file? Or is there something better to use that doesn't give me 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 .cpp?

PS: Here are the reasons why I have thoroughly researched 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, which in my head, as it was already declared in the header file, I could set it in .cpp, in addition to it, the variable dollar_value_was_changed (which was not used) also generated the error that made me ask this question

The errors:

1> toast_notification.obj: error LNK2005: "bool dollar_value_was_changed" (?dollar_value_was_changed @@ 3_NA) already defined in main.obj
1> toast_notification.obj: error LNK2005: "bool toast_notification_was_created" (?doast_notification_was_created @@ 3_NA) already defined in main.obj```
Luiz
  • 119
  • 2
  • 9
  • 1
    ***Why should extern be used in a variable declared in a header file?*** To avoid providing multiple definitions when the header is used in more than 1 source file. – drescherjm Dec 23 '20 at 14:53
  • 1
    A better question is, why do you think you need to declare variables in a header file? Usually global variables are not the answer, far from it. – underscore_d Dec 23 '20 at 14:53
  • 1
    https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files – alex_noname Dec 23 '20 at 14:54
  • 1
    @underscore_d I agree. It's a problem I never have because I almost never define a variable in a header. – drescherjm Dec 23 '20 at 14:54
  • 2
    You're missing the fine distinction between [declarations and definitions](https://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration) – Mat Dec 23 '20 at 14:55
  • 1
    So, to answer the other part of the question - "Is it a good practice to use `extern` in the header file?" - no, because that means you're using global variables, which are widely documented as leading to brittle and difficult-to-analyse code, so rethink your design. – underscore_d Dec 23 '20 at 14:57
  • @underscore_d Why not declare variables in a header file? – Luiz Dec 23 '20 at 15:01
  • 1
    @LuizFernando There is enough writing out there about why global variables are bad that you can search without me having to repeat it here. – underscore_d Dec 23 '20 at 15:02
  • 1
    Related: [https://stackoverflow.com/questions/484635/are-global-variables-bad](https://stackoverflow.com/questions/484635/are-global-variables-bad) – drescherjm Dec 23 '20 at 15:03
  • ok @underscore_d – Luiz Dec 23 '20 at 15:08
  • 1
    @underscore_d: customization point objects and algorithm objects are reasonable global “variables” declared in headers. They’d be `constexpr` objects, though, and as such not particular variable. Maybe namespace scope _objects_ would be a better term. – Dietmar Kühl Dec 23 '20 at 15:09

1 Answers1

2

In C++ a variable declaration at namespace scope is a definition unless it is declared extern. The extern prevents the declaration from being a definition. You can define a variable only once within a program (unless you make it inline). As headers are normally included in multiple translation units you’d get multiple definitions.

Note: I do not recommend to make variables inline! The primary use of inline “variable” definitions is for constexpr objects. In general I advise against non-const global data.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380