【问题标题】:using map in C++ and providing wrapper functions to use that in C在 C++ 中使用 map 并提供包装函数以在 C 中使用它
【发布时间】:2015-04-25 05:41:41
【问题描述】:

在 MSVC6 中,我需要在 C++ 中使用 map 并提供包装函数以在 c 中使用它们来添加、删除和获取大小。我想在不使用 C++ 中的任何类的情况下做到这一点。这将由线程使用,每个线程都有一个结构句柄,该句柄将有一个 void *,它将作为参数传递给 C++ 包装函数,我希望 C++ 代码将此 void * 转换为映射并执行操作。我无法将 void * 转换为 C++ 中的地图,任何解决方案都会有所帮助。

【问题讨论】:

  • 展示你的尝试。通常它是很小的东西,没有它我们都只能疯狂地猜测。我的猜测:void Add(void* mapHandle, const char *key, int value ) { std::map<std::string,int> *pMap = reinterpret_cast<std::map<std::string,int>*>(mapHandle); .... }
  • 是的,你是对的,但我正在使用 static_cast 来转换 void *.转换后map变量不可访问(Access Viaolation)

标签: c++ c dictionary visual-studio-6


【解决方案1】:

我会试一试,因为我喜欢猜测:

我假设您有一个传递给 create thead 函数的函数,看起来像这样:

int callback(void* userdata);

让我们创建一个访问地图的回调函数:

// In the header file: "my_callback.h" we first need to declare that this function will be used from a C file, this is so the compiler will name the function according to the C standard and not C++.
#ifdef __cplusplus
extern "C" {
#endif

// Declare your function:
int my_callback(void * map_handle);

#ifdef __cplusplus
extern "C" {
#endif

现在,确保在 c++ 文件中包含头文件:

#include "my_callback.h"

int my_callback(void * map_handle) {
    // First, for convenience, let us define the map type
    using mapType = std::map<std::string, int>;

    // First cast the void * to a the correct map * pointer
    mapType *mapPtr = static_cast<mapType*>(map_handle);

    mapPtr->insert( "Test", 1 ); // Insert
    cout << (*mapPtr)["Test"];   // read

    // Or you can assign it to a reference to hide away the pointer syntax:
    mapType & mapRef = *static_cast<mapType*>(map_handle);


    mapRef.insert( "Test", 1 ); // Insert
    cout << mapRef["Test"];   // read

    // (...)
}

有几点值得注意:

  1. 我们被允许使用static_cast,因为输入是一个void指针,当你创建线程并静态转换到一个void指针到同类型定义明确。

  2. 这绝不是线程安全的。从多个线程同时访问相同资源时必须特别小心。如果您打算只有一个映射并让所有线程访问该映射,则应包含一个互斥锁以确保一次只有一个线程访问它。一个很好的方法是简单地创建一个包含映射和互斥体的小结构:

    结构 map_n_mutex { mapType 地图; some_mutex_t 互斥体; // 不确定在 windows 上互斥锁的正确类型是什么。 };

在你的线程初始化阶段:

// Create map
map_n_mutex user_data;

// Create thread (I'm making this function up, use what you have been using)
create_thread( my_callback, &user_data); // pass a pointer to userdata

如果您采用这种方法,请记住您需要在回调函数中转换为 map_n_mutex 而不是 mapType

【讨论】:

    【解决方案2】:

    C 代码需要从 C++ 代码中获取 void 指针,类似

    void *get_map_from_cpp();   /* declare the function */
    
    void *our_map = get_map_from_cpp();
    

    get_map_from_cpp() 将被定义为(在 C++ 中)类似的东西;

     #include <map>
     #include <string>
    
     extern "C" void *get_map_from_cpp()
     {
          std::map<std::string, float> *the_map = new std::map<std::string, float>;
          return static_cast<void *>(the_map);
     }
    

    但它并不止于此。要将值插入映射中,我们需要将值传入,例如,在 C 中

      void insert_to_map(void *, const char *str, float f);   /* declaration */
    
      insert_to_map(our_map, "Everything", 42.0);
    

    其中insert_to_map() 也必须在 C++ 中定义,例如

       extern "C" void insert_to_map(void *m, const char *str, float f)
       {
            std::map<std::string, float> *the_map;
    
            the_map = static_cast< std::map<std::string, float> *>(m);
            std::string the_str(str);
            (*the_map)[the_str] = f;
       }
    

    同样,retrieve_from_map() 可以实现为

     extern "C" float retrieve_from_map(void *m, const char *str)
     {
          std::map<std::string, float> *the_map;
    
          the_map = static_cast< std::map<std::string, float> *>(m);
          std::string the_str(str);
    
          std::map<std::string, float>::const_iterator i = the_map->find(the_str);
          if (i != the_map->end())
              return i->second;
          else
              return 0.0f;     // string not found in map, so return 0.0
     }
    

    从 C 调用的函数必须提供纯 C 接口 - 这意味着 C 代码不能直接接触 C++ 类型。其次,到 C++ 的映射必须仅在 C++ 代码中完成,因为 C 编译器不会理解这些结构。这意味着函数必须只接受或返回在 C 中有意义的类型,函数必须为 C++ 编译器声明为 extern "C"(以便可以从 C 调用),并且函数的主体必须处理从将 C 类型转换为 C++。

    这确实依赖于 C 和 C++ 编译器之间的兼容性(例如,来自同一供应商、兼容的 ABI 等)。

    【讨论】:

    • 是的,但问题是在转换映射变量后无法访问它。在 C++ 文件中 extern "C" int wrapper_add_workid_to_map(void *maphnd,int key, int value) { std::map *pMap = static_cast<:map>*>(maphnd); (*pMap)[键] = 值;返回0; } and In C File typedef struct threadhandle { void *workid_map;// 保存原型到映射句柄 }thrhnd; ret = wrapper_add_workid_to_map(hnd.workid_map,1,1);
    • “无法访问”是什么意思?你的代码不是很清楚。
    • 无法访问转换后的映射变量“the_map,意味着无法向此映射变量插入或删除值“抛出访问冲突错误”。
    猜你喜欢
    • 1970-01-01
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 2010-10-26
    相关资源
    最近更新 更多