0

I have one header file that my teacher requires. I am using a global variable so I can move the value from one function to another. Looking up the problem, someone recommended using a namespace. That did not work. Additionally, I added some guards like someone else recommended, but that did not help either. I have multiple files and the commonly accepted solution of extern in header and then the declaration in the .cpp does not work for me for some reason. Global variables in header file

Methods.h


#pragma once
#define METHODS_H
#include <cfguard.h>
#ifdef METHODS_H
#include <iostream>
#include <fstream>
#include <vector>
#include <string>


// declaring global variables
namespace global_variables
{
    int number_of_employees;
}
#endif

One usage of the variable in WSCreate.cpp

// for loop to make sure amount of employees is integer

    int count = 0;
    int triggered = 0;
    while (true){
        
    cout << "Enter the number of employees you would like to enter\n";
    string employees_in_string_format;
    getline (cin, employees_in_string_format);
        for (int i = 0; i < employees_in_string_format.length(); ++i)
        {
            triggered = 0;
            if (isdigit(employees_in_string_format[i]) == false)
            {
                count = 1;
                triggered = 1;
            }
            else
            {
                count = 0;
            }
        }
        if (triggered == 1)
        {
            cout << "One of your inputs for the amount of employees you have is not a positive integer. Please enter \n positive integers\n";
        }

        else if (triggered == 0)
        {
            cout << "Your inputs are validated!\n";
            number_of_employees = stoi(employees_in_string_format);
            break;
        }
}

WSRead.cpp (another usage of this global variable)

 for (int i = 0; i != number_of_employees; i++)
    {
        cout << endl;
        employees >> printing;
        cout << printing << " ";
        employees >> printing;
        cout << printing << "\t  ";
        employees >> printing;
        cout << printing << "\t\t";
        employees >> printing;
        cout << printing << "\t\t";
        employees >> printing;
        cout << printing;
        cout << endl;
    }

Again, sorry if it is a duplicate question, but I could not find the solution to my problem.

Thanks in advance.

If you need more code, let me know.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Unrelated, coming almost immediately after `#define METHODS_H`, is there any doubt about the results of `#ifdef METHODS_H`? – user4581301 Apr 15 '21 at 00:10
  • @πάνταῥεῖ Not sure that a C question is the best duplicate here, and can't find offhand a C++ one to also mention inline variables among the answers. – dxiv Apr 15 '21 at 00:12
  • @dxiv It didn't really help, but I got an answer, and after I got rid of my namespace it worked. – Rohan Parikh Apr 15 '21 at 00:14
  • 1
    @RohanParikh What also works (since C++17) is `inline int number_of_employees;`. – dxiv Apr 15 '21 at 00:17

1 Answers1

3

When exporting global variables, you want them to be defined in your c++ file so that it gets compiled only once by the compiler.

Currently, including it from the .h file adds it to all of your .obj files (built by the compiler) and the linker does not like the same variable existing at multiple places when it tries to build your .exe or library.

What you need to do is to declare the variable as "extern" in the header file, and add its declaration (identical) to an appropriate .cpp file.

in the header :

extern int number_of_employee;

In the .cpp

int number_of_employee;

Additionally, if you want to use a global variable within a .cpp file, but you don't want it to be modifiable by any external files that declare

extern int your_variable_name;

You ought to define it as "static", which means it will not be seen by the linker, and will be "private" to the .obj it's defined in.

Edit (like so):

static int your_variable_name;

Edit (as per @dxiv's comment):

Since c++17, a possibly preferred way of doing this (since it results in less bloat) is to declare your variable as inline - which tells the linker that it is allowed to have multiple declarations and, in case of variables, that all declarations should be merged as a single binary bit of data in the final binary.

inline int number_of_employee;

To make sure you have c++17 or later enabled with msvc++, you can check that you have the /std:c++17 or /std:c++latest flag in your project properties, in visual studio under

project -> properties -> Configuration properties -> General -> C++ Language Standard.

For completion sake, with the GNU or GNU-inspired compilers, you'd need the flag -std=c++17.

Have a nice evening,

Alceste_
  • 592
  • 4
  • 13
  • Thanks for that! This helped! The only thing was I had to get rid of my namespace. Thank you again. – Rohan Parikh Apr 15 '21 at 00:13
  • @RohanParikh You don't have to get rid of the namespace, but you have to keep the namespace consistent between the declaration and definition. – dxiv Apr 15 '21 at 00:19
  • @dxiv What do you mean by that? I had the using namespace (namespace name) in my cpp source files as well. – Rohan Parikh Apr 15 '21 at 00:23
  • 2
    @RohanParikh The definition `int number_of_employees;` must be inside a matching `namespace` block, or explicitly qualified with the namespace name. The `using` directive helps with resolving namespaces, not with associating unqualified definitions to a namespace. – dxiv Apr 15 '21 at 00:27