【问题标题】:How to create an object in C++ that can be referenced globally from C code?如何在 C++ 中创建一个可以从 C 代码全局引用的对象?
【发布时间】:2021-12-17 19:51:44
【问题描述】:

我有一个 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();

【问题讨论】:

  • 您必须将extern "C" 添加到map.cc。 how can I be sure my Map exists and how would I make it global? 为什么不直接运行代码? map.cc 是否包含 map.hmap.cc中没有#include &lt;map&gt;吗?为什么最后一个代码sn-p中的代码在函数之外? EXTERNC 是否受到 #ifdef __cplusplus 的保护?
  • "如果我在我的 C 程序中执行以下调用" - 但你不能这样做。 C 要求所有具有静态存储持续时间的对象都由常量表达式初始化。
  • @KamilCuk 为什么还需要将 extern "C" 添加到 map.cc 中?其余的东西存在于真实文件中,createMap() 是从一个大函数中调用的。
  • 这不是初始化 C++ 对象,而是初始化指针。 C 不允许您在静态对象的初始化程序中调用函数。
  • 关于 C 中的全局指针:保留默认初始化并正确初始化它,就像您在 main 函数中所做的第一件事一样。为此,我推荐一个像往常一样具有 extern 声明的头文件,并将变量定义在与主函数相同的文件中。

标签: c++ c global extern


【解决方案1】:
//How do I let everyone use this pointer
void* ptr = createMap();

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

通常的模式是提供一个执行延迟初始化并返回指针的函数。

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 代码进行检查的错误。无论哪种方式,都不要忽视它们的存在。

【讨论】:

  • 这个宏是幂等的,即它可以被每个调用者使用地图调用还是意味着在别处初始化一个静态ptr? #define globalPtr globalMap()
  • @knowads - 宏和函数本身一样具有幂等性......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 2016-05-09
相关资源
最近更新 更多