简体   繁体   中英

Interpreting Char-Array to Multiple concatenated Datatypes

I receive via Socket a stream of bytes (or chars in C++). Now I want to interprete them. I know which datatypes are hidden behind the bytes. My message looks somehow like that:

value1   --> char (1 byte)
value2   --> long (8 bytes)
value3   --> short (2 bytes)
... 

How can I achieve the interpretation efficiently?

//Edit: that don't work, the bytes don't describe characters but integers.

I thought about doing is with memcpy and atoi (not tested so far):

char value1 = *charPtr;
charPtr++;

char value2[8]="";
std::memcpy(charPtr,value2,8);
long v2 = atoi(value2);
charPtr+=8;

char value3[2]="";
std::memcpy(charPtr,value3,2);
short v3 = atoi(value3);
charPtr+=2;

I assume that you are trying to send data as raw byte stream, and you've been assured that sender and receiver uses the same floating point format and same endiness .

But your packed data stream apparently violates alignment rules on both sender and receiver sides, so we can not do something like value2 = *(long *)data;

So, try using parsePackedStruct(data, &value1, &value2, &value3);

where a reasonable implementation can be:

void parsePackedStruct(char *data, char *pValue1, long *pValue2, short *pValue3)
{
    memcpy(pValue1, data, sizeof(*pValue1));
    data = data + sizeof(*pLalue1);
    memcpy(pValue2, data, sizeof(*pValue2));
    data = data + sizeof(*pLalue2);
    memcpy(pValue3, data, sizeof(*pValue3));
}

This requires your sender and receiver have strictly the same size for char/short/long , which seems too strict to me because size of long varies from platform to platform much more often than other arithmetic types. For the same reason, I'd also avoid bool and use uint8_t .

So consider C99 integer types like int32_t .

Assuming sender and receiver are in perfect sync as to the raw data sent/received, you could do something like this:

#pragma pack(push, 1)
struct MyPackedData {
  char c;
  long l;
  short s;
};
#pragma pack(pop)

...

MyPackedData parsedData;
memcpy(&parsedData, charPtr, sizeof(parsedData));

Okey, I figured out how to do this. The keyword is bit shifting:

long readAndSkipLong(char*& b)
{
    unsigned long ret = (b[0] << 56) | (b[1] << 48) | (b[2] << 40) | (b[3]<<32) | (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | (b[7]);
    b+=8;
    return ret;
}

int readAndSkipInt(char*& b)
{
    int32_t ret = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
    b+=4;
    return ret;
}

short readAndSkipShort(char*& b) {
    short ret =  (b[0] << 8) | (b[1]);
    b+=2;
    return ret;
}

...
while (readChar(it)!='#') // stop at the terminating char
{
        readAndSkipShort(it);
        readAndSkipInt(it);
}
...

Nevertheless my shifting for long and int seems not to be right. For the intended value

152  --> 00000000 00000000 00000000 00000000 00000000 00000000 00000000 10011000

I interpret:

-104  --> 11111111 11111111 11111111 11111111 11111111 11111111 11111111 10011000 

any idea where the bug is?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM