Hi,
I have a client which uses UDP to receive messages on Linux. The messages can be one of the many structures defined by my program. All structures have this format:
struct general_message
{
struct message_header;
unsigned char body[1500];
};
struct message_header has same fields in all structures but the body is different.
My program thus uses a lot of typecasting to typecast the general_message
structure to different structures which can then be processed by functions.
Problem:
How can I avoid heavily used typecasting in my program.
Depending on how your message system works, you could either use a simple inheritance system (one general_message class, other messages derive from it), or you might be able to use polymorphism/virtual functions. It would depend on what exactly is in the "body" section of the other structures however.
By using unions along with struct you can seperate members within your struct.
say for example
you have message_header, body1[500] and body2[1500].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
struct general_message {
struct message_header;
union {
struct {
char a[100]; // considered char is 1 byte
int b[200]; // int is 2 bytes
}body1_struct;
unsignedchar body[500];
}body1;
union {
struct {
char a[200]; // char is 1 byte
int b[100]; // int is 2 bytes
long c [200]; // long is 4 bytes
char d [300]; // char is 1 byte
}body2_struct;
unsignedchar body[1500];
}body2;
};
create general_message object. assign your received message into it. Start reading data depending on structure type. If you want you can add a variable to let you know what type of structure you received. You can do this more better if you think good.
Since the header must be of a fixed format and contain a discriminator that identifies the type of the message body that follows, typically what I do is write a factory that parses just the header then constructs an object of the correct message type to parse the message body. Generally you won't need any typecasting then.
template< typename T >
T Read( std::deque<char>& m )
{
if( m.size() < sizeof( T ) )
throw /* something */;
union {
T val;
char buf[ sizeof( T ) ];
} u;
// Warning: use of operator+ here is not generic:
std::copy( m.begin(), m.begin() + sizeof( T ), u.buf );
m.erase( m.begin(), m.begin() + sizeof( T ) );
return u.val;
}
struct Header {
Header( std::deque<char>& msg ) :
from( Read<int>( msg ) ), msgType( Read<int>( msg ) ) {}
int from;
int msgType;
};
void ParsePacket( std::deque<char> m ) {
try {
Header hdr( m );
switch( m.msgType ) {
/* etc */
}
}
catch( /* what you threw above, plus anything else you want */ ) {
}
}
When I do this, ParsePacket usually returns a type erasure type (http://www.cplusplus.com/forum/articles/18756/) so that I can contain an instance of a specific message object without requiring inheritance and virtual functions at the packet level (they exist internally in the type erasure type), and then the packet has an Execute() method which executes the command/does whatever. (Instead of the "typical" design where some master object knows how to execute each message type).
I set up one program on linux. I configure it. But a problem observes at make. Please help me!
index_set.h: In constructor ‘index_set<T, Cmp>::index_set()’:
index_set.h:19: error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available
index_set.h:19: error: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
index_set.h: In member function ‘void index_set<T, Cmp>::clear()’:
index_set.h:21: error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available
index_set.h: In member function ‘const T& index_set<T, Cmp>::operator[](int) const’:
index_set.h:27: error: there are no arguments to ‘end’ that depend on a template parameter, so a declaration of ‘end’ must be available
index_set.h:27: error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available
index_set.h: In member function ‘const T* index_set<T, Cmp>::operator()(int) const’:
index_set.h:35: error: there are no arguments to ‘end’ that depend on a template parameter, so a declaration of ‘end’ must be available
index_set.h:35: error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available
index_set.h: In member function ‘void index_set<T, Cmp>::remove(int)’:
index_set.h:42: error: there are no arguments to ‘end’ that depend on a template parameter, so a declaration of ‘end’ must be available
index_set.h: In member function ‘void index_set<T, Cmp>::sort()’:
index_set.h:49: error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available
index_set.h:49: error: there are no arguments to ‘end’ that depend on a template parameter, so a declaration of ‘end’ must be available
index_set.h: In member function ‘int index_set<T, Cmp>::position(const typename index_set<T, Cmp>::iterator&) const’:
index_set.h:55: error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available
make[1]: *** [TOpt.o] Error 1
I use versiyon of g++-3.4, gcc-3.4, cpp-3.4, libg2c0-3.4.
A part of make:
g++ -o TOpt.o -c -g -pg -D_DEBUG_ -pthread -m32
-I/home/sule/root/include -I/usr/include/mysql/ -I. TOpt.cc
In file included from TBLWc1TrackContainer.h:17,
from TBLTrack.h:8,
from TBLUtil.h:16,
from TBLWc1SegmentContainer.h:16,
from TBLLinear.h:7,
from TOpt.cc:23:
index_set.h: In constructor 'index_set<T, Cmp>::index_set()':
index_set.h:19: error: there are no arguments to 'begin' that depend
on a template parameter, so a declaration of 'begin' must be available
index_set.h:19: error: (if you use '-fpermissive', G++ will accept
your code, but allowing the use of an undeclared name is deprecated)
index_set.h: In member function 'void index_set<T, Cmp>::clear()':
index_set.h:21: error: there are no arguments to 'begin' that depend
on a template parameter, so a declaration of 'begin' must be available
index_set.h: In member function 'const T& index_set<T,
Cmp>::operator[](int) const':
index_set.h:26: error: there are no arguments to 'size' that depend on
a template parameter, so a declaration of 'size' must be available
index_set.h:27: error: there are no arguments to 'end' that depend on
a template parameter, so a declaration of 'end' must be available
index_set.h:27: error: there are no arguments to 'begin' that depend
on a template parameter, so a declaration of 'begin' must be available
index_set.h: In member function 'const T* index_set<T,
Cmp>::operator()(int) const':
index_set.h:34: error: there are no arguments to 'size' that depend on
a template parameter, so a declaration of 'size' must be available
index_set.h:35: error: there are no arguments to 'end' that depend on
a template parameter, so a declaration of 'end' must be available
index_set.h:35: error: there are no arguments to 'begin' that depend
on a template parameter, so a declaration of 'begin' must be available
index_set.h: In member function 'void index_set<T, Cmp>::remove(int)':
index_set.h:42: error: there are no arguments to 'end' that depend on
a template parameter, so a declaration of 'end' must be available
index_set.h: In member function 'void index_set<T, Cmp>::sort()':
index_set.h:49: error: there are no arguments to 'begin' that depend
on a template parameter, so a declaration of 'begin' must be available
index_set.h:49: error: there are no arguments to 'end' that depend on
a template parameter, so a declaration of 'end' must be available
index_set.h: In member function 'int index_set<T, Cmp>::position(const
typename index_set<T, Cmp>::iterator&) const':
index_set.h:55: error: there are no arguments to 'begin' that depend
on a template parameter, so a declaration of 'begin' must be available
index_set.h: In member function 'int index_set<T, Cmp>::Size() const':
index_set.h:59: error: there are no arguments to 'size' that depend on
a template parameter, so a declaration of 'size' must be available
make[1]: *** [TOpt.o] Error 1
make[1]: Leaving directory `/home/sule/blast/BlastLib2'
make: *** [all] Error 2
Not providing any solution here but just want to recommend messaging structure can be in JSON format. This format is lean and mean and most Web apps can understand it. You may want to consider it although it is for Javascript, it is actually programming language independent.
Having proprietary message structures require other systems to 'talk' the same way but with JSON a replacement for XML format, it is easier for other systems to 'talk' to your system. You only need a C++ JSON parser and you are ready to go.