wham3
wham3

Reputation: 51

How to declare an extern C function inside a function in C++?

I have an inline function, roughly like this:

inline void SomeFunction() {
    extern void SomeOtherFunction();
    SomeOtherFunction();
}

This is a simplification: my functions do have parameters and return values.

However, I want this header to work in both C and C++ files. Currently, linking fails because C++ files attempt to find an implementation of SomeOtherFunction with C++ linkage. I thought I could just fix this by using extern "C":

inline void SomeFunction() {
#ifdef __cplusplus
    extern "C" void SomeOtherFunction();
#else
    extern void SomeOtherFunction();
#endif
    SomeOtherFunction();
}

This causes Clang to fail with:

error: expected unqualified-id
    extern "C" void SomeOtherFunction();
           ^

How can I do this correctly?

Upvotes: 2

Views: 2129

Answers (4)

fukanchik
fukanchik

Reputation: 2865

extern "C" is a linkage-specification. C++ standard section 7.5 Linkage specifications paragraph 4 states that:

A linkage-specification shall occur only in namespace scope (3.3).

E.g. you can say extern "C" in global namespace or some specific namespace. Outside of namespaces it is illegal.

Function declarations are possible though in smaller scopes. If you remove linkage specification your code will compile (but not link):

inline void SomeFunction() {
    extern void SomeOtherFunction();
    SomeOtherFunction();
}

If you really need SomeOtherFunction declaration in a smaller scope (e.g. hide from global scope) you can put your declaration into a header file to a dedicated scope and then use in your function:

Header:

namespace other {
    extern "C" void SomeOtherFunction();
}//namespace other

Code:

void SomeFunction()
{
    other::SomeOtherFunction();
}

Credit goes to these two answers on stackoverflow: here and here.

Upvotes: 6

melpomene
melpomene

Reputation: 85767

From the C++11 standard (in [dcl.link], emphasis mine):

4 Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.

(linkage-specification refers to extern string-literal ..., i.e. extern "C" in your case.)

This means you can't have extern "C" inside of a class or function.

What's the point of declaring SomeOtherFunction inside of SomeFunction? It still has to be a global symbol and visible to the linker.

So why not do this?

#ifdef __cplusplus
    extern "C" 
#endif
void SomeOtherFunction();

inline void SomeFunction() {
    SomeOtherFunction();
}

The following also seems to work:

extern "C" {
    inline void SomeFunction() {
        extern void SomeOtherFunction();
        SomeOtherFunction();
    }    
}

But it would have the side effect of making SomeFunction also use C linkage (which is hopefully OK as (per your requirements) it needs to be usable from C, too).

Upvotes: 4

zupazt3
zupazt3

Reputation: 1046

You can do this like that. I assume you have a header file, a C source and a C++ source.

Header file:

inline void SomeFunction()
{
    void SomeOtherFunction_Bridge();
    SomeOtherFunction_Bridge();
}

C++ source:

extern "C" 
{
    void SomeOtherFunction();
}

void SomeOtherFunction_Bridge()
{
    SomeOtherFunction();
}

C source:

void SomeOtherFunction()
{
    // Function with a code doing something
}

void SomeOtherFunction_Bridge()
{
    SomeOtherFunction();
}

Checked on GCC, it compiles.

Upvotes: 1

BJovke
BJovke

Reputation: 1983

extern tells the compiler that a symbol (function, variable) is defined in some other module. When this module (C++ file) is compiled, object file contains a list of external symbols it needs. So this is on a level of a C++ file, it cannot be in smaller scope (function, block).

Upvotes: -3

Related Questions