开发者

Want to translate/typecast parts of a char array into values

开发者 https://www.devze.com 2023-03-29 08:09 出处:网络
I\'m playing around with networking, and I\'ve hit a bit of a road block with translating a packet of lots of data into the values I want.

I'm playing around with networking, and I've hit a bit of a road block with translating a packet of lots of data into the values I want.

Basically I've made a mockup packet of what I'm expecting my packets to look like a bit. Essentially a Char (8bit value) indicating what the message is, and that is detected by a switch statement which then populates values based off the data after that 8 bit value. I'm expecting my packet to have all sorts of messages in it which may not be in order.

Eg, I may end up with the heartbeat at the end, or a string of text from a chat message, etc.

I just want to be able to say to my program, take the data from a certain point in the char array and typecast (if thats the term for it?) them into what I want them to be. What is a nice easy way to do that?

char bufferIncoming[15];
ZeroMemory(bufferIncoming,15);

//Making a mock packet
bufferIncoming[0] = 0x01; //Heartbeat value
bufferIncoming[1] = 0x01; //Heartbeat again just cause I can
bufferIncoming[2] = 0x10; //This should = 16 if its just an 8bit number, 

bufferIncoming[3] = 0x00; // This
bufferIncoming[4] = 0x00; // and this
bufferIncoming[5] = 0x00; // and this
bufferIncoming[6] = 0x09; // and this should equal "9" of its is a 32bit number (int)

bufferIncoming[7] = 0x00;
bufferIncoming[8] = 0x00;
bufferIncoming[9] = 0x01;
bufferIncoming[10] = 0x00; //These 4 should be 256 I think when c开发者_StackOverflow社区ombines into an unsigned int
//End of mockup packet


int bufferSize = 15; //Just an arbitrary value for now
int i = 0;
while (i < bufferSize)
{
    switch (bufferIncoming[i])
    {
        case 0x01: //Heart Beat
            {
                cout << "Heartbeat ";
            }
            break;
        case 0x10: //Player Data
            {
                //We've detected the byte that indicates the following 8 bytes will be player data. In this case a X and Y position

                playerPosition.X = ??????????; //How do I combine the 4 hex values for this?
                playerPosition.Y = ??????????;
            }
            break;
        default:
            {
                cout << ".";
            }
            break;

    }
    i++;
}
cout << " End of Packet\n";


UPDATE

Following Clairvoire's idea I added the following.

playerPosition.X = long(bufferIncoming[3]) << 24 | long(bufferIncoming[4]) << 16 | long(bufferIncoming[5]) << 8 | long(bufferIncoming[6]);

Notice I changed around the shifting values.

Another important change was

unsigned char bufferIncoming[15]

If I didn't do that, I was getting negative values being mixed with the combining of each element. I don't know what the compiler was doing under the hood but it was bloody annoying.

As you can imagine this is not my preferred solution but I'll give it a go. "Chad" has a good example of how I could have structured it, and a fellow programmer from work also recommended his implementation. But...

I have this feeling that there must be a faster cleaner way of doing what I want. I've tried things like...

playerPosition.X = *(bufferIncoming + 4) //Only giving me the value of the one hex value, not the combined >_<
playerPosition.X = reinterpret_cast<unsigned long>(&bufferIncoming); //Some random number that I dont know what it was

..and a few other things that I've deleted that didn't work either. What I was expecting to do was point somewhere in that char buffer and say "hey playerPosition, start reading from this position, and fill in your values based off the byte data there".

Such as maybe...

playerPosition = (playerPosition)bufferIncoming[5]; //Reads from this spot and fills in the 8 bytes worth of data
//or
playerPosition.Y = (playerPosition)bufferIncoming[9]; //Reads in the 4 bytes of values

...Why doesnt it work like that, or something similar?


There is probably a pretty version of this, but personally I would combine the four char variables using left shifts and ors like so:

playerPosition.X = long(buffer[0]) | long(buffer[1])<<8 | long(buffer[2])<<16 | long(buffer[3])<<24;

Endianness shouldn't be a concern, since bitwise logic is always executed the same, with the lowest order on the right (like how the ones place is on the right for decimal numbers)

Edit: Endianness may become a factor depending on how the sending machine initially splits the integer up before sending it across the network. If it doesn't decompose the integer in the same way as it does to recompose it using shifts, you may get a value where the first byte is last and the last byte is first. It's small ambiguities like these that prompt most to use networking libraries, aha.

An example of splitting an integer using bitwise would look something like this

buffer[0] = integer&0xFF;
buffer[1] = (integer>>8)&0xFF;
buffer[2] = (integer>>16)&0xFF;
buffer[3] = (integer>>24)&0xFF;


In a typical messaging protocol, the most straight forward way is to have a set of messages that you can easily cast, using inheritance (or composition) along with byte aligned structures (important for casting from a raw data pointer in this case) can make this relatively easy:

struct Header
{
    unsigned char message_type_;
    unsigned long message_length_;
};

struct HeartBeat : public Header
{
    // no data, just a heartbeat
};

struct PlayerData : public Header
{
    unsigned long position_x_;
    unsigned long position_y_;
};

unsigned char* raw_message; // filled elsewhere

// reinterpret_cast is usually best avoided, however in this particular
// case we are casting two completely unrelated types and is therefore
// necessary
Header* h = reinterpret_cast<Header*>(raw_message);

switch(h)
{
    case HeartBeat_MessageType:
    break;

    case PlayerData_MessageType:
    {
        PlayerData* data = reinterpret_cast<PlayerData*>(h);
    }
    break;
}


Was talking to one of the programmers I know on Skype and he showed me the solution I was looking for.

playerPosition.X = *(int*)(bufferIncoming+3);

I couldn't remember how to get it to work, or what its called. But it seems all good now.

Thanks guys for helping out :)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号