extern C can not be used at class level?

前端 未结 5 1215
故里飘歌
故里飘歌 2020-12-06 02:22

Just want to confirm in Windows environment, VSTS 2008 + C++ project, we could only apply extern C to function level, not be able to apply to class level (so that all member

5条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-06 02:41

    Looking at a comment you placed on a previous answer ("[M]y question is just whether we could apply extern C at class level so that all functions in the class automatically has C style name mangling?", the answer is 'extern "C" doesn't quite work that way.'

    Syntactically, extern "C" can be applied to either a single statement of a curly-delimited block:

    extern "C" int my_foo(int i)
    {
        ...
    }
    
    extern "C" {
        int my_bar(int i)
        {
            ...
        }
    
        int my_baz(int i)
        {
            ...
        }
    }
    

    It's common to use extern "C" with the appropriate #ifdef __cplusplus guards on entire C headers.

    Semantically, the actual effect of applying extern "C" will only apply to "normal" (i.e., non-class) functions and pointers to functions. Of course you cannot apply it to a C++ template. Nor can you apply it to class methods (because a class method needs to know which object it was called on, and C-style linkage does not have any way to pass that information in to the function).

    It is possible to apply extern "C" on functions that exist in a namespace, but the namespace information will simply disappear when used via C.


    Update

    If you already have a class (we'll use a POD class for simplicity), and you want to make it usable from C, you'll need to apply extern "C" to a function callable in C. Unfortunately this gets ugly even in simple cases:

    // in the header file
    #ifdef __cplusplus
    namespace X {
    #endif
        struct A
        {
            int x;
    #ifdef __cplusplus
            A() : x(5) { }
            int foo()
            {
                 return x += 5;
            }
    #endif
        };
    #ifdef __cplusplus
        extern "C" {
    #endif
            int A_foo(struct A a);
            struct A A_create();
    #ifdef __cplusplus
        }
    }
    #endif
    
    
    // in the .cc file
    #include "try.h"
    
    namespace X {
        extern "C" {
            int A_foo(A* a)
            {
                return a.foo();
            }
    
            A A_create()
            {
                return A();
            }
        }
    }
    
    // in the .c file
    #include 
    #include "try.h"
    
    int main()
    {
        struct A a = A_create();
        printf("%d", A_foo(a));
    }
    

    Using gcc you would compile this as follows:

    • the C++ file: g++ try.cc -c -o try.o
    • the C file : gcc try.c try.o

    There are a few important points:

    • If your C++ file calls into the STL behind the scenes, or calls new or delete (or new[] or delete[]) you will need to link the final program to the C++ runtime library (the command line switch for this in gcc is -lstdc++.
    • You're probably going to want to pass identical optimization flags when compiling both the C and C++ code (optimization can affect the size of the objects, and if the size doesn't match you can get into a lot of trouble). Ditto for multithreading.
    • You can use exceptions all you want in the C++ code, but once they cross C code all bets are off.
    • If you want something more complex you'll probably want to look at the PIMPL pattern.
    • When a struct falls out of scope in C code the C++ destructor is not called (some compilers may promise to do so, but it's not standard). If you need to do any clean up on these objects you'll need to call an extern "C" function that calls the destructor.

    To call the destructor explicitly:

    extern "C" void A_destroy(struct A a)
    {
        a.~A();
    }
    

提交回复
热议问题