-1

vars.cpp:

#pragma once
#include "vars.h"

namespace vars
{
    struct strct
    {
        bool enabled = false;
    };
}

vars.h:

#pragma once

namespace vars
{
    extern struct strct
    {
        bool enabled = false;
    };
}

extern vars::strct *variables = new vars::strct[ 6 ];

I am getting 'vars::strct': 'struct' type redefinition in vars.cpp

What's the issue?

tambre
  • 4,625
  • 4
  • 42
  • 55
J. Doe
  • 1
  • `extern` is used with variables, not types. Perhaps the unusable `extern` keyword is being ignored, the program continues compilation, and finds that `strct` is defined twice. – user4581301 Jun 16 '18 at 22:27
  • 1
    What exactly are you trying to accomplish here? –  Jun 16 '18 at 22:28
  • You get that error message because the code defines it twice. Remove the definition in `vars.cpp` and remove the `extern` from the definition in `vars.h`. – Pete Becker Jun 16 '18 at 22:35

2 Answers2

1

You have defined your struct twice, this clashes with the one definition rule, thus the error. If you include the vars.h file in vars.cpp you will have that struct defined in your vars.cpp file.

Note

You do not need the extern keyword in your vars.h file because you define a struct and not an instance of it to be used globally. See When to use extern in C++ for more information.

Also, you have used #pragma once in your .cpp file. In most cases you do not include .cpp files and thus it is redundant.

Community
  • 1
  • 1
yakobyd
  • 572
  • 4
  • 12
0

There are a couple things going wrong here.

extern is a Storage Class Specifier used as a promise to the compiler that a variable exists even if it has not yet found the definition of it. The variable can be safely used and the linker will take care of tracking where it has been defined later.

You do not need to define a type as extern and you may be receiving a diagnostic telling you this.

So fix 1: Remove extern from the type.

#pragma once

namespace vars
{
    struct strct
    {
        bool enabled = false;
    };
}

extern vars::strct *variables = new vars::strct[ 6 ];

Now when vars.cpp is compiled, vars.h will be includided, transforming vars.cpp into

#pragma once
namespace vars
{
    extern struct strct
    {
        bool enabled = false;
    };
}

extern vars::strct *variables = new vars::strct[ 6 ];
namespace vars
{
    struct strct
    {
        bool enabled = false;
    };
}

And it's obvious that strct is defined twice. Vars.cpp does not need it's own definition. Remove it.

What vars.cpp does need is to make good on the promise that somewhere variables exists, bringing us to problem 2.

extern vars::strct *variables = new vars::strct[ 6 ];

An extern variable is a promise that a variable exists. There is no variables yet, so initializing it is iffy. The compiler seems to allow it, but the compiler allows a lot of human stupidity.

In general you do not want variable definitions in headers because all files that include a header get a copy of the header. #pragma once will make reasonably sure (too my knowledge there are still a few failure cases) that the header only gets included once per Translation Unit. But each translation unit will have its own definition and you're right back into sorting out multiple definition errors.

Fix 2: What you really want is

vars.h

#pragma once

namespace vars
{
    struct strct
    {
        bool enabled = false;
    };
}

extern vars::strct *variables; // variables exists somewhere

and vars.cpp

#include "vars.h"

vars::strct *variables = new vars::strct[ 6 ]; // variables exists here

Now there is one and only one variables and anyone who #include "vars.h" can use it, assuming they compile and link vars.cpp.

Note the #pragma once has been removed from vars.cpp. It is unnecessary. If you find yourself including cpp files, you've gotten lost somewhere. Don't do it.

user4581301
  • 33,082
  • 7
  • 33
  • 54