Search code examples
c++scopeglobalexternmingw-w64

Accessing an extern "C" variable in c++ from another file


I'm using mingw-w64 on Windows 7 Pro 64-bit. In trying to access external variables, after much hair tearing, I finally arrived at this:

// MultiTest2.h
// Version 1.0.0
// MDJ 2016/04/13

#ifndef MULTITEST2_H
#define MULTITEST2_H

extern "C" {
    int iXfer;
    int setInt();
}

#endif // MULTITEST2_H

does NOT work (I'm using 'extern "C"' instead of just 'extern' because I'm working towards linking to assembly code eventually), but:

// MultiTest2.h
// Version 1.0.1
// MDJ 2016/04/13

#ifndef MULTITEST2_H
#define MULTITEST2_H

extern "C" int iXfer;
extern "C" int setInt();

#endif // MULTITEST2_H

DOES work!

FYI, the other two files in the system are:

// MultiTest2.cpp
// Version 1.0.0
// MDJ 2016/04/13

#include "MultiTest2.h"

int iXfer = 0;

int setInt() {
    iXfer = 6253;
    return 0;
}

and:

// MultiTest1.cpp
// Version 1.0.0
// MDJ 2016/04/13

#include <iostream>
#include "MultiTest2.h"

using namespace std;

int main() {
    setInt();
    cout << iXfer << endl;
}

With Version 1.0.0 of MultiTest2.h (the declarations in an 'extern "C"' block), immediately upon entering:

g++ -S MultiTest2.cpp

the result is:

MultiTest2.cpp:7:5: error: redefinition of 'int iXfer'
 int iXfer = 0;
     ^
In file included from MultiTest2.cpp:5:0:
MultiTest2.h:12:6: note: 'int iXfer' previously declared here
  int iXfer;
      ^

But, with Version 1.0.1 of MultiTest2.h (individual 'extern "C"' declarations), the following sequence works perfectly:

c:\work\gccWork\MultiTest>g++ -S MultiTest2.cpp
c:\work\gccWork\MultiTest>g++ -S MultiTest1.cpp
c:\work\gccWork\MultiTest>g++ -c MultiTest2.s
c:\work\gccWork\MultiTest>g++ -c MultiTest1.s
c:\work\gccWork\MultiTest>g++ -o MultiTest.exe MultiTest2.o MultiTest1.o
c:\work\gccWork\MultiTest>MultiTest
6253

Is this some sort of mingw-w64 idiosyncracy, or is there something I'm missing here?


Solution

  • They are not the same.

    extern "C" int foo;
    

    Does TWO things: it declares that foo is extern (i.e. this is a declaration only, and the symbol will be defined by another module), and it declares the linking of foo as "C", which influences the symbol name.

    On the other hand,

    extern "C" {
      int foo;
    }
    

    only declares that foo has C linking. It does not declare the symbol as extern, which means that this is a definition, not just a declaration.

    In other words

    extern "C" int foo;
    

    is the same as (note the repetition of the extern keyword)

    extern "C" {
      extern int foo;
    }