10

Is it possible to declare a function with C linkage without it having external linkage? When trying to compile

extern "C" static void f() {}

I get

f.cc:1: error: invalid use of 'static' in linkage specification

which makes sense, in a way. In namespace { extern "C" void f() {} }, the extern specifier seems to override the anonymous namespace's restricted scope.

If this is not possible, does it matter when passing a function pointer to C?

Fred Foo
  • 355,277
  • 75
  • 744
  • 836

3 Answers3

11

You can do

extern "C" {
  static void f() {}
}

This will give the function f's type C linkage which in practice means that it uses the C calling convention on your platform. The function's name will still have C++/internal linkage, because a language linkage specification only applies to function names of external linkage.

If you specify the extern "C" directly on the declaration, the Standard specifies that the extern "C" is taken to be also a storage class specifier, so if you would add static, then you would get a conflict.

Does it matter when passing a function pointer to C

It can theoretically matter - an implementation is allowed to differ in behavior from calling a function whose type has C++ linkage to calling a function whose type has C linkage. I don't know of implementation details though, just what the spec says about it. Best to follow the spec and you are safe.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Exactly what I wanted: `undefined reference to 'f'` ;) Why didn't I think of this. Thanks! – Fred Foo Jun 10 '11 at 23:38
  • "an implementation is allowed to differ in behavior" -- I was specifically thinking of functions that take `char` arguments and the C rule that such arguments are promoted to type `int`. – Fred Foo Jun 10 '11 at 23:48
  • @larsmans oh such things are done as specified by c++ laws. that is, if you say `extern "C" void f() { }` then calling `f('a')` is not allowed in C++. So the issue dos not arise. And if you say `extern "C" void f(char x) { }`, then calling `f('a')`, it behaves just as in C. In C, a function `void f(char x) { }` called by `char y = 'a'; f(a)` also passes `y` as a char, no promotion happens. But the actual argument passing (i.e order of parameter allocation on stack, register use, etc) may be different. – Johannes Schaub - litb Jun 10 '11 at 23:54
  • of course if you have a C function `void f(char x) { }` and declare that function as `extern "C" void f(int x);` in C++, you do it wrong - both need to use `f(char x)` or both `f(int x)`. Or you need to define your C function as `void f(x) char x; { }` (which will be compatible with the C++ version taking `int`). – Johannes Schaub - litb Jun 10 '11 at 23:58
  • I've put in an `extern "C"` block to be on the safe side. – Fred Foo Jun 11 '11 at 00:13
  • Re function pointers: IIRC there has only been one real-world system with different ABIs for C and C++ - perhaps Solaris? – o11c Aug 25 '17 at 01:05
0

I just successfully used Johannes answer. Thanks dude!

Since I cannot (yet) comment, but can answer, let me just add this data point.

I typed, in <the-file>.cpp (details mercifully omitted :-) :

extern "C" {
    extern int myfunction(<the-args>);
}

extern int myfunction(<the-args>) {
    <the-code>
}

and also:

extern "C" {
    static int myfunction(<the-args>);
}

static int my function(<the-args>) {
    <the-code>
}

I compiled both ways, and did a:

nm -g <the-file>.o | grep myfuncion

on the two object files in turn.

I observed that for extern, the was an entry, but for the static case, there was none.

So I am happy enough for now that the outer "extern" just sets up the linkage, and the addressing mode is static for the static case.

davernator
  • 240
  • 1
  • 4
0

You can pass the function pointer to a C++ non-member or static member function into a C function and should just work unless you specified a different calling convention for that C++ function. Regular C++ function should use the C calling convention so you're good on that front.

The main reason passing a pointer to a non-static member function doesn't work that easily is because you'll somehow need to pass the information about the object's this pointer as well, which normally happens as an implicit, non-visible parameter for any member function.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70