extern C不能在课堂上使用?

时间:2022-12-31 18:05:56

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 functions from the class use C language name mangling)? I have tried several ways, but always compile error.

只想在Windows环境下确认VSTS 2008 + C ++项目,我们只能将extern C应用到功能级别,而不能应用于类级别(这样所有成员函数都从类中使用C语言名称修改)?我尝试了几种方法,但始终编译错误。

thanks in advance, George

乔治,提前谢谢

5 个解决方案

#1


12  

You can sort of apply extern "C" to a member function via a very convoluted (but entirely legal) hack:

您可以通过一个非常复杂(但完全合法)的黑客将extern“C”应用于成员函数:

extern "C" typedef int bar_t(int x);

struct foo {
     bar_t bar; // yes, this declares a nonstatic member function!
};

int foo::bar(int x) { return x; } // definition

This is possible according to ISO C++03 9.3[class.mfct]/9:

这可以根据ISO C ++ 03 9.3 [class.mfct] / 9:

a member function can be declared (but not defined) using a typedef for a function type. The resulting member function has exactly the same type as it would have if the function declarator were provided explicitly, see 8.3.5.

可以使用typedef为函数类型声明(但未定义)成员函数。结果成员函数与明确提供函数声明符时的类型完全相同,见8.3.5。

However, this doesn't really buy you anything, because of ISO C++03 7.5[dcl.link]/4:

但是,由于ISO C ++ 03 7.5 [dcl.link] / 4,这并不能真正为你买任何东西。

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

对于类成员的名称和类成员函数的成员函数类型,将忽略C语言链接。

#2


5  

extern "c" uses c-style linking; that is, the raw function name is what exposed from the library. Because it is just a raw function name, none of the C++-only features will work with it, including methods or extern data members in namespaces, classes, structs or unions.

extern“c”使用c风格的链接;也就是说,原始函数名称是从库中公开的。因为它只是一个原始函数名,所以只有C ++的功能才能使用它,包括名称空间,类,结构或联合中的方法或外部数据成员。

Clarifying: Structs and unions are in C, but have no member functions, so their member functions in C++ cannot be exported in a c-style (and the struct and union definitions need not be exported, since it is already in the header)

澄清:结构和联合在C中,但没有成员函数,因此它们在C ++中的成员函数不能以c风格导出(并且不需要导出结构和联合定义,因为它已经在标题中)

#3


4  

I'm afraid not. But if you want to pass an object of C++ to C functions, you may refer to this link: http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.8

恐怕不是。但是如果你想将C ++的对象传递给C函数,你可以参考这个链接:http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.8

#4


3  

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

看看你在前一个答案上发表的评论(“问题是我们是否可以在类级别应用extern C,以便类中的所有函数自动具有C样式名称修改?”,答案是'extern' C“并不是那么好用。”

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

从语法上讲,extern“C”可以应用于卷曲分隔块的单个语句:

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.

在整个C头上使用带有相应#ifdef __cplusplus保护的extern“C”是很常见的。

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

从语义上讲,应用extern“C”的实际效果仅适用于“正常”(即非类)函数和指向函数的指针。当然,您无法将其应用于C ++模板。你也不能将它应用于类方法(因为类方法需要知道调用它的对象,并且C风格的链接没有任何方法将该信息传递给函数)。

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.

可以在命名空间中存在的函数上应用extern“C”,但是当通过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:

如果你已经有了一个类(我们将使用POD类来简化),并且你想让它可以从C中使用,你需要将extern“C”应用于可在C语言中调用的函数。不幸的是,这甚至变得难看在简单的情况下:

// 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 <stdio.h>
#include "try.h"

int main()
{
    struct A a = A_create();
    printf("%d", A_foo(a));
}

Using gcc you would compile this as follows:

使用gcc你可以编译如下:

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

  • the C file : gcc try.c try.o
  • C文件: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++.
  • 如果您的C ++文件在后台调用STL,或调用new或delete(或new []或delete []),则需要将最终程序链接到C ++运行时库(gcc中的命令行开关是-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.
  • 在编译C和C ++代码时,您可能想要传递相同的优化标志(优化会影响对象的大小,如果大小不匹配,则会遇到很多麻烦)。多线程也是如此。

  • You can use exceptions all you want in the C++ code, but once they cross C code all bets are off.
  • 您可以在C ++代码中使用所有您想要的异常,但是一旦它们跨越C代码,所有的赌注都会关闭。

  • If you want something more complex you'll probably want to look at the PIMPL pattern.
  • 如果你想要更复杂的东西,你可能想看看PIMPL模式。

  • 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.
  • 当结构超出C代码的范围时,不会调用C ++析构函数(某些编译器可能会保证这样做,但它不是标准的)。如果你需要对这些对象进行任何清理,你需要调用一个调用析构函数的extern“C”函数。

To call the destructor explicitly:

要显式调用析构函数:

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

#5


2  

Ummm... extern "C" forces C-style linkage. It cannot be used with classes AFAIK.

嗯... extern“C”强制C式联动。它不能用于AFAIK类。

#1


12  

You can sort of apply extern "C" to a member function via a very convoluted (but entirely legal) hack:

您可以通过一个非常复杂(但完全合法)的黑客将extern“C”应用于成员函数:

extern "C" typedef int bar_t(int x);

struct foo {
     bar_t bar; // yes, this declares a nonstatic member function!
};

int foo::bar(int x) { return x; } // definition

This is possible according to ISO C++03 9.3[class.mfct]/9:

这可以根据ISO C ++ 03 9.3 [class.mfct] / 9:

a member function can be declared (but not defined) using a typedef for a function type. The resulting member function has exactly the same type as it would have if the function declarator were provided explicitly, see 8.3.5.

可以使用typedef为函数类型声明(但未定义)成员函数。结果成员函数与明确提供函数声明符时的类型完全相同,见8.3.5。

However, this doesn't really buy you anything, because of ISO C++03 7.5[dcl.link]/4:

但是,由于ISO C ++ 03 7.5 [dcl.link] / 4,这并不能真正为你买任何东西。

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

对于类成员的名称和类成员函数的成员函数类型,将忽略C语言链接。

#2


5  

extern "c" uses c-style linking; that is, the raw function name is what exposed from the library. Because it is just a raw function name, none of the C++-only features will work with it, including methods or extern data members in namespaces, classes, structs or unions.

extern“c”使用c风格的链接;也就是说,原始函数名称是从库中公开的。因为它只是一个原始函数名,所以只有C ++的功能才能使用它,包括名称空间,类,结构或联合中的方法或外部数据成员。

Clarifying: Structs and unions are in C, but have no member functions, so their member functions in C++ cannot be exported in a c-style (and the struct and union definitions need not be exported, since it is already in the header)

澄清:结构和联合在C中,但没有成员函数,因此它们在C ++中的成员函数不能以c风格导出(并且不需要导出结构和联合定义,因为它已经在标题中)

#3


4  

I'm afraid not. But if you want to pass an object of C++ to C functions, you may refer to this link: http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.8

恐怕不是。但是如果你想将C ++的对象传递给C函数,你可以参考这个链接:http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.8

#4


3  

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

看看你在前一个答案上发表的评论(“问题是我们是否可以在类级别应用extern C,以便类中的所有函数自动具有C样式名称修改?”,答案是'extern' C“并不是那么好用。”

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

从语法上讲,extern“C”可以应用于卷曲分隔块的单个语句:

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.

在整个C头上使用带有相应#ifdef __cplusplus保护的extern“C”是很常见的。

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

从语义上讲,应用extern“C”的实际效果仅适用于“正常”(即非类)函数和指向函数的指针。当然,您无法将其应用于C ++模板。你也不能将它应用于类方法(因为类方法需要知道调用它的对象,并且C风格的链接没有任何方法将该信息传递给函数)。

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.

可以在命名空间中存在的函数上应用extern“C”,但是当通过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:

如果你已经有了一个类(我们将使用POD类来简化),并且你想让它可以从C中使用,你需要将extern“C”应用于可在C语言中调用的函数。不幸的是,这甚至变得难看在简单的情况下:

// 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 <stdio.h>
#include "try.h"

int main()
{
    struct A a = A_create();
    printf("%d", A_foo(a));
}

Using gcc you would compile this as follows:

使用gcc你可以编译如下:

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

  • the C file : gcc try.c try.o
  • C文件: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++.
  • 如果您的C ++文件在后台调用STL,或调用new或delete(或new []或delete []),则需要将最终程序链接到C ++运行时库(gcc中的命令行开关是-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.
  • 在编译C和C ++代码时,您可能想要传递相同的优化标志(优化会影响对象的大小,如果大小不匹配,则会遇到很多麻烦)。多线程也是如此。

  • You can use exceptions all you want in the C++ code, but once they cross C code all bets are off.
  • 您可以在C ++代码中使用所有您想要的异常,但是一旦它们跨越C代码,所有的赌注都会关闭。

  • If you want something more complex you'll probably want to look at the PIMPL pattern.
  • 如果你想要更复杂的东西,你可能想看看PIMPL模式。

  • 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.
  • 当结构超出C代码的范围时,不会调用C ++析构函数(某些编译器可能会保证这样做,但它不是标准的)。如果你需要对这些对象进行任何清理,你需要调用一个调用析构函数的extern“C”函数。

To call the destructor explicitly:

要显式调用析构函数:

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

#5


2  

Ummm... extern "C" forces C-style linkage. It cannot be used with classes AFAIK.

嗯... extern“C”强制C式联动。它不能用于AFAIK类。