Hi,

I need some help in converting the struct pointer to void pointer, since I do not want to expose the whole structure coming from one interface to the other.

I need some help in coding callSetInt() and callSetString() methods in the below code. The set() method hides the structures and just sends a void pointer.

#include <iostream>
#include <string>
using namespace std;

typedef struct AttrValue {
  union {
    int32_t   i32;
    int16_t   i16;
    char*   theString;
  } value;
} AttrValueT;


typedef enum AttrType {
      AttrType_INT32 = 1,
      AttrType_INT16 = 2,
      AttrType_theString = 3
} AttrTypeT;

 
 typedef struct AttrValueContainer {
      AttrType type;
      unsigned int nrOfValues;
      struct AttrValue *values;
 } AttrValueContainerT;

/* ##################################################################################
 * */

void callSetInt (int noOfVal, void *p)
{
  // decode the void pointer based on number of values.
  // for simpler test,  i32 is considered.

  int* p1 = static_cast<int*>(p);

  for (int i=0; i< noOfVal; ++i)
 {
    cout << *(p1+i)<<endl; 
 }

 //Note that *(p1+0) works and not others... Needs to solve this

}

void callSetString(int noOfVal,  void *p)
{
 cout <<"in call set string"<<endl;
 cout <<static_cast<char*>(p); //doesn't work..

}

void set ( AttrValueContainerT *val)
{
   int n = val->nrOfValues;
   int type = (int)val->type;
 
   //send it as a void pointer to hide the structs from the inner classes
    void *p = val->values;

   if (type == 3)
   {
     callSetString(n, p);
   }
   else
   {
    callSetInt(n, p);
   }
}

 /* ##################################################################################3*/

int main()
{
  // test for set() method
  AttrValueContainerT va1, val2;

  val1.nrOfValues = 2;
  val1.type = (AttrType)1;
  val1.values = new AttrValue[val1.nrOfValues];
  val1.values[0].value.i32 = 888;
  val1.values[1].value.i32 = 999;
  set(&val1);


  val2.nrOfValues = 2;
  val2.type = (AttrType)3;
  val2.values = new AttrValue[val2.nrOfValues];
  val2.values[0].value.theString = "cat";
  val2.values[1].value.theString = "mat";
  set(&val2);

  return 0;
}

Thanks,
Ranvi

Can you explain why you want to "hide" the structure from the SetInt and SetString functions? This is a really dirty trick and should hardly ever be necessary in C++...

Can you explain why you want to "hide" the structure from the SetInt and SetString functions? This is a really dirty trick and should hardly ever be necessary in C++...

I agree this might not be the right way of doing things. But unfortunately, I have to.. We have an interface between C and C++.. The client is sending the data in those structures.. But we are not supposed to expose the whole structures to the other interface. Hence the set() method comes into picture. The set() method decodes the structure and sends the value.

I am really stuck at this point.. Need help to solve this asap.. Thanks a lot.

I have written a simple example which shows how you can use the void pointer to pass an integer value. Maybe this will be of help

void func(void* p)
{
     int *x= (int* )p;
     printf("%d\n",*x);
}

int main(int argc, char* argv[])
{
    int x=10;
    void* p= &x;
    func(p);
            
	cin.get();
	
	return 0;
}

Hi Abhimanipal,

Thanks ffor the response. I am quite familiar with how the void pointers work with the simple data types like int, float etc. But I am not able to solve the same with the structures given in the code. It would be great if I can get some help over there.

Thanks,
Ranvi

Unless your union has members which are all the same size, you're stuck.

When you assign values to your array via the union (for the shorter types), you get a lot of holes in memory which are not filled in.

However, when you try to recast that as a pointer to a short type, all those holes disappear and you end up looking for data in the wrong places.

// Assigned
+===v===+===v===+
|888. ? |999. ? |
+===^===+===^===+

// Read
+===v===+===v===+
|888. 0 |   .   |
+===^===+===^===+

Your code...

#include <iostream>
#include <string>
using namespace std;

typedef struct AttrValue {
  union {
    int32_t   i32;
    int16_t   i16;
    const char*   theString;
  } value;
} AttrValueT;


typedef enum AttrType {
  AttrType_INT32 = 1,
  AttrType_INT16 = 2,
  AttrType_theString = 3
} AttrTypeT;


typedef struct AttrValueContainer {
  AttrType type;
  unsigned int nrOfValues;
  struct AttrValue *values;
} AttrValueContainerT;

/* ##################################################################################
* */

void callSetInt (int noOfVal, void *p)
{
  cout <<"in call set int32_t"<<endl;
  int32_t* p1 = static_cast<int32_t*>(p);
  
  for (int i=0; i< noOfVal; ++i)
  {
    cout << p1[i]<<endl;
  }
}

void callSetShort (int noOfVal, void *p)
{
  cout <<"in call set int16_t"<<endl;
  int16_t* p1 = static_cast<int16_t*>(p);
  
  for (int i=0; i< noOfVal; ++i)
  {
    cout << p1[i]<<endl;
  }
}

void callSetString(int noOfVal,  void *p)
{
  cout <<"in call set string"<<endl;
  char  **p1 = static_cast<char**>(p);
  for (int i=0; i< noOfVal; ++i)
  {
    cout << p1[i]<<endl;
  }
}

void set ( AttrValueContainerT *val)
{
  int n = val->nrOfValues;
  int type = (int)val->type;
  
  //send it as a void pointer to hide the structs from the inner classes
  void *p = val->values;
  switch ( type ) {
    case AttrType_INT32:
      callSetInt(n, p);
      break;
    case AttrType_INT16:
      callSetShort(n, p);
      break;
    case AttrType_theString:
      callSetString(n, p);
      break;
  }
}

/* ##################################################################################3*/

int main()
{
  // test for set() method
  AttrValueContainerT val1, val2;
  
  val1.nrOfValues = 2;
  val1.type = AttrType_INT32;
  val1.values = new AttrValue[val1.nrOfValues];
  val1.values[0].value.i32 = 888;
  val1.values[1].value.i32 = 999;
  set(&val1);
  
  val1.nrOfValues = 2;
  val1.type = AttrType_INT16;
  val1.values = new AttrValue[val1.nrOfValues];
  val1.values[0].value.i16 = 888; //!! there is a hole in memory between
  val1.values[1].value.i16 = 999; //!! 888 and 999
  set(&val1);
  
  val2.nrOfValues = 2;
  val2.type = AttrType_theString;
  val2.values = new AttrValue[val2.nrOfValues];
  val2.values[0].value.theString = "cat";
  val2.values[1].value.theString = "mat";
  set(&val2);
  
  return 0;
}

Hi Salem,

Thanks a lot for the response.. This solved my major bit of the problem. But still I have a question. The method callSetInt()/callSetShort() just prints the first value and not the rest (here 888 and not 999). What should I do to print all the values? Should I pass the sizeof the structure to those methods in order to decode all the values? or is there any other way of achieving the same?

Thanks a lot,
Ranvi

But you could solve that, if you know the size of the biggest type in the structure right?

Let's say 32 bit int is the largest type and you are reading a 16bit int.
Instead of advancing the pointer by 'size of a 16 bit int' you would advance it by 'size of a 32 bit int' to get to the next element.


Edit:

In this case it might just be easiest to fire up a debugger and look at your structure in memory.. see what the p1 is pointing to and what it points to after increasing it. That way you should be able to see what's going wrong.

Passing the size of the union would allow you to perform the necessary calculation to work out where the next element is stored.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.