-1

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

4

2 回答 2

0

C 代码将需要void从 C++ 代码中获取指针,执行类似的操作

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

void *our_map = get_map_from_cpp();

whereget_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);

whereinsert_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;
   }

类似地,aretrieve_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 中有意义的类型,函数必须像extern "C"C++ 编译器一样声明(以便可以从 C 调用),并且函数的主体必须处理来自 C 类型的映射到 C++。

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

于 2015-04-25T06:20:40.790 回答
0

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

我假设您有一个传递给 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 指针,然后从 void 指针到相同类型的定义是明确的。

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

    struct 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在回调函数内部。

于 2015-04-25T06:18:55.543 回答