You can't pass a pointer to a structure that contains a std::string
member to msgrcv
, this violates the interface contract.
The second parameter passed to msgrcv
needs to point to a buffer with sufficient space to store a 'plain' C struct of the form struct { long mtype; char mdata[size]; };
where size is the third parameter to msgrcv
.
Unfortunately, determining the size of this buffer might depend on size
due to possible alignment issues but you have to assume that it doesn't on a system that provides this sort of interface. You can use the standard offsetof
macro to help determine this size.
As a vector
stores its components contiguously, once you know the size of the buffer, you can resize a vector
of char
and use this to hold the buffer. Using a vector
relieves you of the obligation to free
or delete[]
a buffer manually.
You need to do something like this.
std::string RecvMessage()
{
extern size_t size; // maximum size, should be a parameter??
extern int MSGQ_ID; // message queue id, should be a parameter??
extern long MSG_ID; // message type, should be a parameter??
// ugly struct hack required by msgrcv
struct RawMessage {
long mtype;
char mdata[1];
};
size_t data_offset = offsetof(RawMessage, mdata);
// Allocate a buffer of the correct size for message
std::vector<char> msgbuf(size + data_offset);
ssize_t bytes_read;
// Read raw message
if((bytes_read = msgrcv(MSGQ_ID, &msgbuf[0], size, MSG_ID, 0)) < 0)
{
throw MsgRecvFailedException();
}
// a string encapsulates the data and the size, why not just return one
return std::string(msgbuf.begin() + data_offset, msgbuf.begin() + data_offset + bytes_read);
}
To go the other way, you just have to pack the data into a struct
hack compatible data array as required by the msgsnd interface. As others have pointer out, it's not a good interface, but glossing over the implementation defined behaviour and alignment concerns, something like this should work.
e.g.
void SendMessage(const std::string& data)
{
extern int MSGQ_ID; // message queue id, should be a parameter??
extern long MSG_ID; // message type, should be a parameter??
// ugly struct hack required by msgsnd
struct RawMessage {
long mtype;
char mdata[1];
};
size_t data_offset = offsetof(RawMessage, mdata);
// Allocate a buffer of the required size for message
std::vector<char> msgbuf(data.size() + data_offset);
long mtype = MSG_ID;
const char* mtypeptr = reinterpret_cast<char*>(&mtype);
std::copy(mtypeptr, mtypeptr + sizeof mtype, &msgbuf[0]);
std::copy(data.begin(), data.end(), &msgbuf[data_offset]);
int result = msgsnd(MSGQ_ID, &msgbuf[0], msgbuf.size(), 0);
if (result != 0)
{
throw MsgSendFailedException();
}
}