Safe, efficient way to access unaligned data in a network packet from C

*爱你&永不变心* 提交于 2019-12-05 16:43:36

To avoid alignment issues in this case, access all data as an unsigned char *. So:

unsigned char *p;
//...
uint16_t id = p[0] | (p[1] << 8);
p += 2;

The above example assumes "little endian" data layout, where the least significant byte comes first in a multi-byte number.

Michael Burr

You should have functions (inline and/or templated if the language you're using supports those features) that will read the potentially unaligned data and return the data type you're interested in. Something like:

uint16_t unaligned_uint16( void* p)
{
    // this assumes big-endian values in data stream
    //  (which is common, but not universal in network
    //  communications) - this may or may not be 
    //  appropriate in your case

    unsigned char* pByte = (unsigned char*) p;

    uint16_t val = (pByte[0] << 8) | pByte[1];

    return val;
}

The easy way is to manually rebuild the uint16_ts, at the expense of speed:

uint8_t *packet = ...;
uint16_t fieldID = (packet[0] << 8) | packet[1];  // assumes big-endian host order
uint16_t length = (packet[2] << 8) | packet[2];
uint8_t *data = packet + 4;
packet += 4 + length;

If your processor supports it, you can type-pun or use a union (but beware of strict aliasing).

uint16_t fieldID = htons(*(uint16_t *)packet);
uint16_t length = htons(*(uint16_t *)(packet + 2));

Note that unaligned access aren't always supported (e.g. they might generate a fault of some sort), and on other architectures, they're supported, but there's a performance penalty.

If the packet isn't aligned, you could always copy it into a static buffer and then read it:

static char static_buffer[65540];
memcpy(static_buffer, packet, packet_size);  // make sure packet_size <= 65540
uint16_t fieldId = htons(*(uint16_t *)static_buffer);
uint16_t length = htons(*(uint16_t *)(static_buffer + 2));

Personally, I'd just go for option #1, since it'll be the most portable.

Alignment is always going to be fine, although perhaps not super-efficient, if you go through a byte pointer.

Setting aside issues of endian-ness, you can memcpy from the 'real' byte pointer into whatever you want/need that is properly aligned and you will be fine.

(this works because the generated code will load/store the data as bytes, which is alignment safe. It's when the generated assembly has instructions loading and storing 16/32/64 bits of memory in a mis-aligned manner that it all falls apart).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!