9

The following C++ code compiles with Visual C++ and g++:

struct S
{
    static void foo();
};

extern "C"
void S::foo() {}

struct T
{
    static void foo();
};

extern "C"
void T::foo() {}

auto main() -> int
{
    S().foo();
    T().foo();
}
  • Is it valid?

  • If it's valid, since the implementation may be in a separate translation unit, does that imply that a static member function always has the same calling convention as a C function (and if not, how does it not imply that)?

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Interesting... It [seems to compile](http://coliru.stacked-crooked.com/a/5ecd60b6f5331a78) and if I've understood point #7 of [this answer](https://stackoverflow.com/a/1041880/865719) correctly, _`extern "C"` is ignored_ in this case. Also, on [cppreference.com](http://en.cppreference.com/w/cpp/language/language_linkage#Special_rules_for_.22C.22_linkage), it is mentioned that "When class member declarations and member function type declarations appear in a "C" language block, their linkage remains "C++"" – maddouri Dec 02 '15 at 07:57

3 Answers3

9

C++11 7.5/4 "Linkage specifications"

A C language linkage is ignored in determining the language linkage of the names of class members and the function type of class member functions.

So your example is valid in the sense that it's not malformed or an error, but the extern "C" should have no effect on S::foo() or T::foo().

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
4

A static member function has the same calling convention as a C function. But, name mangling applies. So, even if you get away with declaring your static member as extern "C", the linker would probably not find it when you try to link it against the C code that calls that function.

What you can easily do is declare a wrapper/stub that calls the static member from a plain function. Also, you can assign the static member function's address to a plain function pointer.

JFMR
  • 23,265
  • 4
  • 52
  • 76
Hellmar Becker
  • 2,824
  • 12
  • 18
  • 2
    Note that while in practice a static member function usually has the same calling convention as a C function, that's not guaranteed by the standard. And while I don't know the details, see the comments in this SO answer for one instance where that has apparently been the case: http://stackoverflow.com/a/1738425/12711 – Michael Burr Dec 02 '15 at 08:11
  • The example you are quoting is trying to convert a nonstatic member function to a plain function. That will not work because of the implicit this pointer in the member function. – Hellmar Becker Dec 02 '15 at 08:14
  • I meant the comment that said, "Unfortunately I have been bitten by the static method not having the same calling convention as the 'C' function...". That comment was posted in response to an earlier edit of the answer that mentioned that a static member function would generally work as well as an `extern "C"` function. – Michael Burr Dec 02 '15 at 08:46
0

No it is ignored, the problem is name mangling (function naming for linkage phase). So the trick is to define a C function and use your C++ static method as a stub to call it, like this:

struct S
{
    static void foo();
};

extern "C" void S_foo_impl();
void S::foo() { S_foo_impl(); }

auto main() -> int
{
    S::foo();
}

Of course, S_foo_impl should be defined in a external C module.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • Given that the code in the question not only compiles but also links OK, I don't quite see how the name mangling can be a problem. To me the standard's wording "A C language linkage is ignored in determining the language linkage of the names of class members and the function type of class member functions." (given in [another answer](http://stackoverflow.com/a/34037483/464581)) indicates that the only part of `extern "C"` that is honored is the `extern`, and that's the default anyway. Am I missing something? – Cheers and hth. - Alf Dec 02 '15 at 09:09
  • To be able to link correctly with overloading, C++ mangles function names by coding types in the name, i.e. a C++ function like `int f(float)` is named something like `f_int_float` in an object module, this to be able to retrieve the right function. Remember that linkers usually know nothing about types. Declaring `extern "C"` in C++, prevent the name mangling. When you define a C++ method, by definition it should be mangled (`extern "C"` is ignored for it). This the trick is to use a global function (not a method of any kind) declared as C linkage. Is this clearer? – Jean-Baptiste Yunès Dec 02 '15 at 09:15
  • Thanks, I know what name mangling is. And as mentioned, there's no linking problem with the above. Just to be sure I tested with separate compilation and function return values, and it works fine with both Visual C++ and g++, contrary to how it would be without name mangling. – Cheers and hth. - Alf Dec 02 '15 at 09:26
  • It works because you compile everything in C++. You can't compile in C a function named like `S::foo`. `extern "C"` is to mix C++ and C. If you compile all your code in C++; it is exactly like you never defined `extern "C"`. Am I missing something? – Jean-Baptiste Yunès Dec 02 '15 at 09:30
  • 1
    Oh, I see. OK, you're missing the most common reason for `extern "C"`, namely to define a callback with C language binding (and calling convention, although in practice it's the same). I didn't even think of having C code call the function by name, but now I see that's what you're talking about. Sorry. – Cheers and hth. - Alf Dec 02 '15 at 09:32