在 C++ 中使用 map,并提供包装函数以在 C 语言中使用它
using map in C++ and providing wrapper functions to use that in C
在 MSVC6 中,我需要在 C++ 中使用 map,并提供包装函数以在 c 中使用它们,仅用于添加、删除和获取大小。我想在不使用任何类的情况下C++这样做。这将由线程使用,每个线程都有一个结构句柄,该句柄将有一个void *
,该句柄将作为参数传递给C++包装器函数,我希望C++代码将此void *
转换为映射并进行操作。我无法将void *
转换为地图,C++任何解决方案都会有所帮助。
我要试一试,因为我喜欢猜测:
我假设你有一个传递给创建 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
// (...)
}
有几点值得注意:
我们被允许使用
static_cast
因为输入是一个void
指针,您应该在创建线程时传递目标映射的地址,并静态转换为 void 指针,然后从 void 指针到同一类型是明确定义的。这绝不是线程安全的。同时从多个线程访问同一资源时必须特别小心。如果您打算只有一个映射并让所有线程访问该映射,则应包含互斥锁以确保一次只有一个线程访问它。一个漂亮的方法是简单地创建一个包含映射和互斥锁的小结构:
结构map_n_mutex { 地图类型地图; some_mutex_t互斥锁;不确定窗口上互斥锁的正确类型是什么。 };
在线程初始化阶段:
// 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
回调函数内部。
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 等)。
- 将 N-arg 函数包装到另一个函数中
- 将函数包装器转换为 std::function
- C++函数包装器来捕获某些信号
- 考虑引用和常量的可变参数函数包装器
- 将此私有删除器函数包装在结构中的目的是什么?
- 处理模板函数包装中的void返回
- 如何使用可变模板编写通用函数包装器
- 其他成员函数的通用"成员函数"包装器?
- 为什么将函数包装到 lambda 中可能会使程序更快?
- 创建一个允许轻松创建虚拟函数包装器函数的C++宏
- 将 c++ 函数包装为 c#,具有结构的总动态大小
- 返回对 std::函数包装的 lambda 中静态变量的引用会导致段错误
- 标准库中是否有与 std::thread 的构造函数语义匹配的类型擦除函数包装器?
- 如何编写 C++ 类成员函数包装器
- 有没有一种方法可以在基于枚举的可变参数模板函数之间进行选择,这比将函数包装在结构中更简单
- 任何返回类型的可变参数函数包装器
- 具有临时函数包装器的完美转发
- 推导成员函数包装器的返回类型时出错
- 使用可变参数模板函数包装基于省略号的函数
- 将C 模板构造函数包装在模板类中