当前位置:  开发笔记 > 编程语言 > 正文

extern C不能在班级使用?

如何解决《externC不能在班级使用?》经验,为你挑选了3个好方法。

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

乔治,提前谢谢



1> Pavel Minaev..:

您可以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语言链接.



2> Todd Gardner..:

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

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



3> Max Lybbert..:

看看您对先前答案的评论(“ [问题是我们是否可以extern C在类级别应用,以便该类中的所有函数自动具有C样式名称修饰?”,答案是' extern "C"不太这样工作。”

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

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 
#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();
}

推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有