反序列化函数(将字节数组转换为 uint32 类型)

6

如何编写反序列化函数将字节数组转换为32位无符号整数?

    typedef unsigned long  uint32;

    uint32 deserialize_uint32(unsigned char *buffer)
    {
        uint32 value = 0;

        value |= buffer[0] << 24;
        value |= buffer[1] << 16;
        value |= buffer[2] << 8;
        value |= buffer[3];
        return value;

    }

    unsigned char* deserialize_uint32B(unsigned char *buffer, uint32* value)
    {
        *value = 0;

        *value |= buffer[0] << 24;
        *value |= buffer[1] << 16;
        *value |= buffer[2] << 8;
        *value |= buffer[3];
        return buffer + 4;
    }

感谢!如果有更好的方法,请告诉我。谢谢!

3
由于它只是一个字节数组,因此似乎一个简单的 value = *(uint32*)buffer; 就能够运作。 - Mark Wilkins
6
如果 buffer 没有指向正确对齐的内存地址,这段看似聪明的代码将会引发未定义行为 - Roland Illig
2
如果unsigned long不是32位,你应该使用uint32_t(来自stdint.h); 为了安全起见,您还应该添加一个编译时断言,即CHAR_BIT == 8 - David X
4
此外,如果数据的大小端与您的主机不同,则此类型的转换会产生错误的值。 - nos
4个回答

5
我更喜欢您提供的第一种方法而不是第二种。或者您可以通过使用四个本地变量,这些变量接受按正确数量移位的各个字节来利用并行处理。然后,在最后一行中,您可以return b0shifted | b1shifted | b2shifted | b3shifted
无论如何,这都取决于您的编译器。您的第二种方法包含更多的加载/存储操作,因此第一种方法具有较少的抽象操作。
就可读性,易理解性和清晰度而言,您的第一种方法非常好。只要CHAR_BIT == 8,它也适用于您正在使用的任何奇怪平台(尾数,对齐)。

3
如果满足输入的 unsigned char 值在0到255之间(包括边界),即使 CHAR_BIT > 8,这个程序也可以正常工作。 - caf

1

可以巧妙地使用强制类型转换来轻松实现此操作。只需将char缓冲区转换为所需的类型即可。

uint32 deserialize_uint32(unsigned char *buf)
{
    uint32 *x = (uint32*)buf;
    return *x;
}

unsigned char * deserialize_uint32B(unsigned char *buffer, uint32* value)
{
    *(uint32*)buffer = *value;
    return buffer;
}

3
你的代码调用了未定义的行为。原帖中从未说明 buf 总是正确对齐的,因此你不能假设它是这样的。 - Roland Illig

1

你的第一种方法可能会产生更好的代码,因为在第二种方法中,编译器必须假定指针datavalue可以别名(尽管如果编译器能够将函数内联使用,则可以缓解此问题)。

如果您有C99编译器,您可能希望利用uint32_tinline和对于第二个变量,restrict


使用uint32_t和我现在使用的有什么区别?此外,这段代码将被移植到另一个使用TI MSP 430的环境中。 - emge
1
uint32_t 的优点仅在于它是 C 标准的一部分,因此您无需为新平台定义它而担忧。 - caf

-1

你可以写:

#include <arpa/inet.h>

uint32_t deserialize_uint32(unsigned char *buffer) {
    uint32_t res = *((uint32_t *) buffer);
    return ntohl(res);
}

unsigned char *serialize_uint32(unsigned char *buffer, uint32_t *value) {
    *((uint32_t *) buffer) = htonl(*value);
    return buffer;
}

这个实现确保字节顺序是正确的,与底层架构无关。


5
并不是每一种情况都适用,因为缓冲区可能会指向某个地址,并没有被正确地对齐以适应“int”类型。 - Roland Illig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接