extern C 不能在类级别使用吗?

发布于 2024-07-25 07:36:01 字数 141 浏览 4 评论 0原文

只是想确认一下,在Windows环境下,VSTS 2008 + C++项目,我们只能将extern C应用于函数级别,而不能应用于类级别(以便类中的所有成员函数都使用C语言名称修改)? 我尝试了多种方法,但总是编译错误。

提前致谢, 乔治

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.

thanks in advance,
George

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橪书 2024-08-01 07:36:02

查看您对之前答案的评论(“[M]y 问题只是我们是否可以在类级别应用 extern C 以便类中的所有函数自动具有 C 样式名称修饰?” ,答案是“extern "C" 不太适合这种方式。”

从语法上讲,extern "C" 可以应用于 curly- 的单个语句。分隔块:

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

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

    int my_baz(int i)
    {
        ...
    }
}

通常在整个 C 标头上使用 extern "C" 和适当的 #ifdef __cplusplus 防护。

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

可以应用extern "C" 存在于命名空间中的函数,但是当通过 C 使用时,命名空间信息将简单地消失。


更新

如果您已经有一个类(我们将使用 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));
}

使用 gcc 可以按如下方式编译:

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

有几个要点:

  • 如果您的 C++ 文件在幕后调用 STL,或者调用 newdelete (或 new[]delete[]),您需要将最终程序链接到 C++运行时库(gcc 中的命令行开关是 -lstdc++
  • 在编译 C 和 C++ 代码时,您可能希望传递相同的优化标志(优化会影响对象的大小,如果大小不匹配,您可能会遇到很多麻烦)。 多线程也是如此。
  • 您可以在 C++ 代码中使用您想要的所有异常,但是 一旦他们跨过 C 代码,一切就都结束了
  • 如果您想要更复杂的东西,您可能需要查看 PIMPL 模式。
  • 当结构超出 C 代码中的范围时,不会调用 C++ 析构函数(某些编译器可能承诺这样做,但这不是标准的)。 如果需要对这些对象进行任何清理,则需要调用 extern“C”函数来调用析构函数。

显式调用析构函数:

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

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 <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:

  • 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();
}
鹿港小镇 2024-08-01 07:36:02

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

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

葬花如无物 2024-08-01 07:36:02

嗯... extern "C" 强制 C 风格的链接。 它不能与类 AFAIK 一起使用。

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

所谓喜欢 2024-08-01 07:36:01

您可以通过非常复杂(但完全合法)的 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

根据 ISO C++03 9.3[class.mfct]/9,这是可能的:

可以使用函数类型的 typedef 来声明(但不能定义)成员函数。 生成的成员函数与显式提供函数声明符时的类型完全相同,请参阅 8.3.5。

然而,这并不能真正给你带来任何好处,因为 ISO C++03 7.5[dcl.link]/4:

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

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

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:

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.

However, this doesn't really buy you anything, because of 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.

最笨的告白 2024-08-01 07:36:01

extern "c" 使用 c 样式链接; 也就是说,原始函数名称是从库中公开的。 因为它只是一个原始函数名称,所以任何 C++ 专用功能都无法使用它,包括命名空间、类、结构或联合中的方法或外部数据成员。

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

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.

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文