3

I have a simple header that contains the following:

// system.h
#pragma once
namespace System
{
    void Initialize(void);
    int (*Main)(int& argc, char** argv);
    void Shutdown(void);
}

In "system.cpp", Initialize() is defined so that the function pointer Main(int,char**) is set to another main function which is determined by preprocessor defines to whatever system this is going to be compiled on (Windows, for now).

In the program's main.cpp, it calls the three functions above...

So when this is compiled, I get a linker error (for system.cpp) complaining that System::Main(int,char**) has already been defined in main.cpp. What's up with this?

~

// system.cpp
#include "..\system.h"
#ifdef _WINDOWS
#include "windows.h"
#else
#define SYSTEM_UNKNOWN 1
#endif
void System::Initialize(void)
{
#ifdef WINDOWS
    System::Main = &Windows::Main;
#else if SYSTEM_UNKNOWN
    System::Main = NULL;
#endif
}

void System::Shutdown(void)
{
    System::Main = NULL;
}

I added the 'extern' keyword to the header... And still no go.

2
  • Tried the 'extern'... No go :/ I get unresolved external symbol errors... Which is odd. Since it's defined in system.cpp! Commented Dec 19, 2013 at 19:04
  • Ok! Apparently I haven't have the definition in the initialize function... Which is, unpleasant. Commented Dec 19, 2013 at 19:14

4 Answers 4

3

The

int (*Main)(int& argc, char** argv);

is a definition of the variable Main. For a declaration, you need extern:

extern int (*Main)(int& argc, char** argv);

and move the definition in an implementation file.

You can try the same (with the same effect) with a simpler example:

int x;

which is also a definition.

Sign up to request clarification or add additional context in comments.

3 Comments

Ah, the joy of C: where you can say extern int private_variable; and modify global variables in someone else's .c file.
@Joker_vD static keyword?
@Joker_vD: If that private_variable was declared with external linkage, then it wasn't really private. But it is true, C has rather crude black-and-white linkage privacy model: it is either internal (potentially accessible by anyone) or external (accessible by no one else).
2

Your Main above isn't just a declaration. It is also a definition. If you include this header in multiple files, each one will define a version of Main. You want to declare the variable as extern and later define it in one .cpp file:

namespace System {
    extern int (*Main)(int&, char**); // declaration
}

int (*Main)(int&, char**) = ...; // definition

Comments

1

You have a typical run-of-the-mill multiple definition error, which is triggered by the fact that you defined a variable with external linkage in header file (and then included that headr file into mutiple translation units). The namespace has nothing to do with it and makes no difference whatsoever.

When you added the extern keyword to the header you turned all these definitions into non-defining declarations. The linker error immediately became different. Now instead of multiple-definition error you got a missing-definition error.

Adding extern keyword in the header was a step in the right direction. Now you just have to create a definition for your variable

int (*Main)(int& argc, char** argv);

in one (and only one) implementation file.

Comments

0

The line int (*Main)(int& argc, char** argv); should not be read the way you read a function forward-declaration, like the other two lines in that code box. This line defines a data variable, called Main, which has type "pointer to function returning int taking blah blah blah." It is analogous to saying int j; in a header file.

As others have said, adding extern in front of it, and then having the line as it is now in a single cpp file, will solve your problems. However I think it's informative to understand the reason behind this behavior.

Edit: This is a side point, but there is probably no reason to pass argc as a reference in this case: you don't save memory because a pointer and an int are probably the same size or worse, and it suggests to the reader that you may modify argc in your Main function, in a way that needs to be reflected back in main from which I presume Main gets called, which I guess I suspect is not the case.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.