-1

In MSVC6 I need to use map in C++ and provide wrapper functions to use them in c only to add,delete and to get size. I want to do this without using any classes in C++. This will be used by threads, Each thread will have a structure handle which will have a void * which will be passed as a parameter to the C++ wrapper functions and I want C++ code to convert this void * to a map and do the operations. I am not able to convert the void * to a map in C++ any solution would be helpful.

Anthon
  • 69,918
  • 32
  • 186
  • 246
Yogeswaran K
  • 51
  • 2
  • 9
  • 1
    Show your attempt. Typically it is something small and without that we all can only guess wildly. My guess: ``void Add(void* mapHandle, const char *key, int value ) { std::map *pMap = reinterpret_cast*>(mapHandle); .... }`` – BitTickler Apr 25 '15 at 05:47
  • yeah you are correct but am using static_cast to conver the void *. After converting the map variable is not accessible to access it(Access Viaolation) – Yogeswaran K Apr 25 '15 at 11:17

2 Answers2

0

I'm gonna give this a shot, because I like guessing:

I assume you have a function that is passed to the create thead function looking something like this:

int callback(void* userdata);

So lets make a callback function accessing a map:

// 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

Now, in the c++ file make sure you include the headerfile:

#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

    // (...)
}

There are a few things that are worth noting:

  1. We are allowed to use static_cast because the input is a void pointer you should be passing the address of the target map when you create the thread and statically casting to and then from a void pointer to the same type is well defined.

  2. This is in no way thread-safe. Special care has to be made when accessing the same resource from multiple threads at the same time. If you intend to have only one map and let all threads access that one, you should include a mutex to ensure that only one thread is accessing it at a time. A nifty way to do this is to simply create a small struct including the map and a mutex:

    struct map_n_mutex { mapType map; some_mutex_t mutex; // Not sure what the correct type for a mutex would be on windows. };

In your thread initialization phase:

// 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

If you go by this approach, remember that you need to cast to map_n_mutex and not mapType inside the callback function.

Stian Svedenborg
  • 1,797
  • 11
  • 27
0

The C code will need to obtain the void pointer from the C++ code, doing something like

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

void *our_map = get_map_from_cpp();

where get_map_from_cpp() would be defined (in C++) as something like;

 #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);
 }

It doesn't stop there though. To insert values into the map, we need to pass values in, for example, in C

  void insert_to_map(void *, const char *str, float f);   /* declaration */

  insert_to_map(our_map, "Everything", 42.0);

where insert_to_map() must also be defined in C++, for example as

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

Similarly, a retrieve_from_map() might be implemented as

 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
 }

The functions called from C must provide a C-only interface - this means C code cannot directly touch C++ types. Second, the mapping to C++ must be done in exclusively in C++ code, since a C compiler will not understand the constructs. That means the functions must accept or return only types that make sense in C, the functions must be declared as extern "C" for the C++ compiler (so they can be called from C), and the body of the function must handle the mapping from the C types to C++.

This does rely on compatibility between the C and C++ compilers (e.g. from the same vendor, compatible ABI, etc).

Peter
  • 35,646
  • 4
  • 32
  • 74
  • yes but the prob is after converting the map variable not able to access it. In C++ File extern "C" int wrapper_add_workid_to_map(void *maphnd,int key, int value) { std::map *pMap = static_cast*>(maphnd); (*pMap)[key] = value; return 0; } and In C File typedef struct threadhandle { void *workid_map;// this hold the prototype to map handle }thrhnd; ret = wrapper_add_workid_to_map(hnd.workid_map,1,1); – Yogeswaran K Apr 25 '15 at 11:22
  • What do you mean by "not able to access it"? Your code does not that clear. – Peter Apr 25 '15 at 11:26
  • not able to access the casted map variable "the_map, means not able to insert or delete values to this map variable "Access Violation errror is thrown". – Yogeswaran K Apr 27 '15 at 06:28