如何在 C++ 中创建一个可以从 C 代码全局引用的对象?

How to create an object in C++ that can be referenced globally from C code?

我有一个用 C 语言编写的大型程序,我想将某些 C++ 对象与地图等一起使用。 我按照 this post 如何从 C 调用 C++,我的两个 C++ 看起来像这样。

///map.cc
#include "map.h"

void* createMap()
{
    std::map<int,int> *m = new std::map<int,int>();
    return static_cast<void*>(m);
}
void putInMap(int key, int value, void* opaque_map_ptr){
    std::map<int,int> *m = static_cast<std::map<int,int>*>(opaque_map_ptr);
    m->insert(std::pair<int,int>(key,value));
}

//map.h
 #ifdef __cplusplus
 #define EXTERNC extern "C"
 #else
 #define EXTERNC
 #endif


EXTERNC void* createMap();

EXTERNC void putInMap(int key, int value, void* opaque_map_ptr);

我不清楚的是,如果我在我的 C 程序中执行以下调用,我如何确定我的 Map 存在以及如何使其成为全局的?我只是让相应的指针成为全局指针吗?

#include "map.h"
//How do I let everyone use this map
void* ptr = createMap();
//How do I let everyone use this pointer
void* ptr = createMap();

不是通过声明一个初始化器为 = createMap() 的全局对象。 C 不允许 C++ 具有的那种全局变量的动态初始化。指针必须由常量表达式初始化。如果你想在 C 中调用 createMap(),它只能在输入 main 并且函数调用明确后发生。

通常的模式是提供一个执行惰性初始化的函数和 returns 一个指针。

void *globalMap() {
    static void *ptr = NULL;
    if (!ptr)
        ptr = createMap();
    return ptr;
}

调用代码然后可以使用 globalMap() 获取指向对象的共享指针。如果需要“类似对象”的语法,则可以使用宏来包装函数调用

#define globalPtr globalMap()

可以通过 errno 查看标准示例。

另一件必须提到的事情是我写了一个非常幼稚的globalMap(),因为指针赋值不是线程安全的。 使其成为线程安全的并非不可能,但代码会稍微复杂一些。您可以让 C++ 编译器隐式完成它(C++11 及更高版本)。该技术就是所谓的 Meyers Singleton

extern "C" void *globalMap() {
    static std::map<int, bool> m;
    return &m;
}

就是这样。 C++ 编译器将对其进行检测,使得 m 仅初始化一次且没有竞争条件。


最后一点,不要忘记您必须在 ABI 边界上处理 C++ 异常!在正确的位置使用一些 noexcept 说明符使它们全部致命是一种方法,或者将它们转换为可能返回到 C 代码以供检查的错误。不管怎样,都不要忽视他们的存在。