简体   繁体   中英

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?

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).

Eg 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 (eg 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 .

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 ... , ie 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).

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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM