Link to home
Start Free TrialLog in
Avatar of ambuli
ambuliFlag for United States of America

asked on

Void pointers

Hi there,

When a function expects void pointer, can I pass in a pointer to an object to it. I am using a queue API(don't have the code).  The Queue has the following functions.  

Receive (void* pMsgBuffer, int size);
Send (const void* pMsgBuffer,int size)



If I want to pass in 'tc' below and then at the receiving side copy to tc2.  Can I do these??

TestClass *tc = new TestClass( );

TestClass tc2r;

Send(tc, sizeof(TestClass))
Receive(&tc2, sizeof(TestClass))

Avatar of sunnycoder
sunnycoder
Flag of India image

Hi ambuli,

> When a function expects void pointer, can I pass in a pointer to an object to it
Yes you can ... The code snippets you posted would work fine ... any pointer can be casted to a void * and void * can be cast to pointer of any other type. const may give you a warning which can be avoided by an explicit cast.

Cheers!
sunnycoder
Avatar of ambuli

ASKER

Thanks SunnyCoder,

Here is a little expanded version. I am having problems with the following code.  Please help.  The problem is that when I print the member, expecting to see 100, it becomes empty.  

class A
{
   public:
      virtual void setmember( )=0;
      virtual void printMember( );
 };

class B : public A
{
public:
    void setMember( int x){ m_b = x; };
    void printMember( cout << "member = " << m_b << endl;
private:
    int m_b;
};

class C
{
       testSend( A *a) { Send(a, sizeof(A) ); };
       testReceive( A *a) { Receive( a, sizeof(A)) };

};

main()
{
    C  *cc = new C( )

    B *bb = new B( );
    B  bb2;
    bb->setMember(100);
    cc->testSend(bb, sizeof(A));
    cc->testReceive(&bb2, sizeof(A));
    bb2.printMember();

}
Hi ambuli,

You are calling printMember() on bb2 and you have not initialized bb2!!
Also, this is not the exact code you are using ... this wont compile!!

Cheers!
sunnycoder
Hi Ambuli,

The void * pointer is a place-holder pointer which any pointer type can be converted to, this is used so that any data type can be put on the "queue" in your example.

In your code:

TestClass *tc = new TestClass( );
TestClass tc2r;

Send(tc, sizeof(TestClass))
Receive(&tc2, sizeof(TestClass))

This might work but we cannot just pass any pointer in this case, unless you have control over the functions Send & Receive just because we don't know how "tc" will be reinterpreted in side the function. If there is an SDK and it expects only 2 or 3 verities of void pointers then its fine.When I say 2 or 3 verities of void pointer, it means, for examole an object of TestClass1 or TestClass2 or TestClass3.

Hope I get across.

Best Regards,
DeepuAbrahamK


Avatar of ambuli

ASKER

Yes, it is not the exact code.  The code is very long to post here.  
Even if changing it didn't help.

   B  *bb2 = new B( );
   bb->setMember(100);
   cc->testSend(bb, sizeof(A));
   cc->testReceive(bb2, sizeof(A));
   bb2->printMember();
Hi ambuli,

>    B  *bb2 = new B( );  ----- allocated bb2
>    bb->setMember(100);        ---- set bb
>    bb2->printMember();          ----- print bb2!!!!

I dont see void * or class C playing any role here ... If you are observing some unexpected behavior, look for flaws in the logic of the code ... casting to and from void * wont cause any problems as long as you are correctly handling the data which these pointers are pointing to.

Cheers!
sunnycoder
hi,
  I found mistake over here,
>>  void printMember( cout << "member = " << m_b << endl;

void PrintMember() { cout << "member = " << m_b << endl;}

Deepu

ASKER CERTIFIED SOLUTION
Avatar of numansiddique
numansiddique

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Take heed of Alex's advice, but as long as your class is a self-contained bunch of bits (or POD = plain old data class) you can serialise and deserialise by doing bitwise copies. Beware that if you are doing this over the network your receipient may have different endianism, different word sizes and different packing from your sender. So it is a bad plan.

e.g. Illustration:
--------8<--------
#include <iostream>
#include <string>
using namespace std;

class BunchOfBits;
ostream& operator<<(ostream& os,const BunchOfBits&);

class BunchOfBits {
      char name[100];
      int value;
      friend ostream& operator<<(ostream& os,const BunchOfBits&);

public:
      BunchOfBits(const string& name,int value) : value(value) {
            strncpy(BunchOfBits::name,name.c_str(),sizeof(BunchOfBits::name)-1);
            BunchOfBits::name[sizeof(BunchOfBits::name)-1] = '\0';
      }
};

ostream& operator<<(ostream& os,const BunchOfBits& bob) {
      return os << "Bob '" << bob.name << "' born " << bob.value;
};

char network_buffer[1024];
size_t occupied = 0U;

size_t send(const void *data,size_t length)
{
      if (occupied)
            return 0U;
      if (length > sizeof(network_buffer))
            length = sizeof(network_buffer);
      memcpy(network_buffer,data,length);
      occupied = length;
      return length;
}

size_t receive(void *data,size_t length)
{
      if (!occupied)
            return 0U;
      if (length > occupied)
            length = occupied;
      memcpy(data,network_buffer,length);
      occupied = 0U;
      return length;
}

int main()
{
      BunchOfBits first("Robert The Bruce",1274);
      BunchOfBits second("Robert Louis Stevenson",1894);
      BunchOfBits third("Robert Smith (The Cure)",1959);

      cout << "1st: " << first << ", 2nd: " << second << ", 3rd: " << third << '\n';

      send(&first,sizeof(BunchOfBits)); // Let's send the first Bob
      receive(&third,sizeof(BunchOfBits)); // And receive him as the 3rd

      cout << "1st: " << first << ", 2nd: " << second << ", 3rd: " << third << '\n';
}
--------8<--------
Avatar of grg99
grg99

You really can't in general pass objects as voids.  Objects can have very complex internal info, such as pointers to virtual method tables-- stuff that doesnt make any sense outside of the sending program.

You CAN send the fields of an object, if you explicitly list them and their lengths, but that gets cumbersome.

A better solution is to encapsulate all thee data into a sepoarate struct, then send that.
>>>> you can serialise and deserialise by doing bitwise copies.

Instead of bitwise copies - what rarely is an option - you should provide member functions to serialize and deserialize together with your class, e. g. together with an intelligent buffer or stream class like the one below.

Regards, Alex


struct Buffer
{
     Buffer(unsigned int siz) : m_siz(siz), m_len(0), m_pBuf(new unsigned char[siz+1]) {}
       ~Buffer() { delete [] m_pBuf; }

       operator void*() { return m_pBuf; }
       Buffer&  operator += (const Buffer& b)
       {
          int nlen = m_len + b.m_len;
          if (m_siz < nlen)
            {
               unsigned char* pBuf = new unsigned char[nlen + nlen];
               memcpy(pBuf, m_pBuf, m_len);
               m_siz = nlen + nlen;
               delete [] m_pBuf;
               m_pBuf = pBuf;
            }
            memcpy(&m_pBuf[m_len], b.m_pBuf, b.m_len);
            m_len += b.m_len;
            return *this;
       }

       Buffer&  operator -= (unsigned int len)
       {
           if (b.m_len > len)
             memmove(b, &b.m_pBuf[slen], b.m_len - slen);
             b.m_len -= len;
             return *this;
       }
       int            size() { return m_size; }
       int m_siz;
       int m_len;
       unsigned char* m_pBuf;
};

Buffer& operator<<(Buffer& b, const string& s)
{
    int  len = s.length()+1;
    Buffer temp(len + sizeof(int));
      memcpy(temp, &len, sizeof(int));
      memcpy(temp, s.c_str(), len);
      return b += temp;
}

Buffer& operator<<(Buffer& b, int i)
{
    Buffer temp(sizeof(int));
      memcpy(temp, &i, sizeof(int));
      return b += temp;
}

Buffer& operator<<(Buffer& b, const char* s)
{
    b << string(s);
      return b;
}

Buffer& operator<<(Buffer& b, const X& x)
{
    Buffer temp(sizeof(X));  // take sizeof X as approximate size
      x.serialize(temp);
   
      return b += temp;
}

Buffer& operator>>(Buffer& b, string& s)
{
    int slen;
      memcpy(&slen, b, sizeof(int));
      b -= sizeof(int);  // cut length info

      s = (const char*)(void*)b; // assume zero-terminated strings only

      b -= slen;
    return b;
}

Buffer& operator>>(Buffer& b, int& i)
{
      memcpy(&i, b, sizeof(int));
      b -= sizeof(int);  // cut length info
      return b;
     
}

Buffer& operator>>(Buffer& b, char* psz)
{
    string s;
    b >> s;
      strcpy(psz, s.c_str());
      return b;
}

Buffer& operator>>(Buffer& b, X& x)
{
    b = x.deserialize(b);
    return b;    
}



class A
{
     
public:  
     Buffer& serialize(Buffer b);
       Buffer& deserialize(Buffer& buf);
private:
     string m_s;
       int    m_i;
       char   m_c[100];
       X      m_x;
       // more ...
};

Buffer& A::serialize(Buffer& b)
{
   b << m_s << m_i << m_c << m_x;
   return b;
}

Buffer& A::deserialize(Buffer& b)
{
   b >> m_s >> m_i >> m_c >> m_x;
   return b;
}


int main()
{
      A a1;  
      
      // fill data
    a1.fill();

    Buffer buf1(sizeof(A));
      a1.serialize(buf1);
    send(buf1, buf1.m_len);

      ....

      A a2;

    Buffer buf2(MAX_SIZ_TO_RECEIVE);
    receive(buf2, buf2.m_siz);
      a2.deserialize(buf2);

      // note, the receive buffer can contain more data

      ...

      return 0;

}
I'm really not promoting bitwise serialising, because it is bad for all the reasons listed above, but if you are using the approach, because "you know the layout of your bits" (snigger), you have an opportunity to play with placement construction.

With reference to my previous code example, see how we can receive fourth from a sent BunchOfBits using placement construction:

      char fourth_buf[sizeof(BunchOfBits)];
      receive(&fourth_buf,sizeof(BunchOfBits));  
      BunchOfBits& fourth = *new(fourth_buf) BunchOfBits();      // Placement ctor

Note that you need a default Ctor for BunchOfBits to do placement construction thus. That's something I omitted.

Placement construction can be used to "construct" objects from suitably laid out raw memory. It is of course not managed by the heap in this case, which is why you see me make fourth a reference.