如何将UUID转换为大端序?

6

我的 UUID 结构如下:

struct UUID_FIELDS
{
    uint32_t time_low;                
    uint16_t time_mid;                 
    uint16_t time_hi_and_version;      
    uint8_t clock_seq_hi_and_reserved;
    uint8_t clock_seq_low;             
    uint8_t node[6];                   

};

我有一些函数可以沿32位边界进行交换和一个可以沿16位边界进行交换的swap function。我试图在time_low上调用swap32(),在time_midtime_hi_and_version上调用swap16()。我认为我不需要交换其余字段的字节,因为其中两个字段是8位字段,并且我已经读到uuid的节点部分不会改变。这里是一个相关的链接
问题在于当我完成交换后,打印出来的uuid与在转换前的小端字节序的uuid不匹配。
从小端转换为大端,正确的方法是什么?转换后的uuid应该与原始的uuid匹配吗?请遵循RFC-4122标准。

请查看:在线十六进制转换器 - BattleTested_закалённый в бою
如果你的系统是小端序的,并且按照RFC-4122标准接收UUID(大端序表示),那么你需要交换time_lowtime_midtime_high_and_version上的字节才能正确使用它们。 - kmdreko
2
@MohammadrezaPanahi 你可能需要说明一下该转换网站如何与原帖的问题有关(我可以补充说,原帖问得很清晰)。这是一个有用的网站,但它如何帮助解决这个问题呢? - WhozCraig
你知道数据是小端序的吗?还是机器本地顺序?你可能想使用htonlhtons而不是无条件地进行字节交换,这样你就不会在已经是大端序的机器上执行交换。 - ShadowRanger
1
用像0x01020304等内容制作一个UUID,并为每个32位、16位和字节的每个字节使用唯一的字节值。然后进行交换并发送到另一端,并打印所有值(或使用调试器等查看)。这将显示字节最终停留在哪里:0x01到达的位置,0x02等等。查看原始结构,本地交换的结构和远程接收的结构。 - Kaz
显示剩余11条评论
3个回答

4

回复:

Update: Starting uuid in little endian:

446831D3-FBA1-477B-BB07-CB067B00E86B

Result from correctly swapping necessary fields:

FBA1477B-31D3-4468-6BE8-007B06CB07BB

这看起来非常不对。我们可以推断,如果交换是正确的且只影响32位和16位字段,则在不交换必要字段的情况下,它将变成这样:

Original: 446831D3-FBA1-477B-BB07-CB067B00E86B
           |       _______/   |       _______/
            \____ /_______     \____ /______
            _____/        \    _____/       \
           /               |  /              |
Received: 7B47A1FB-D331-6844-6BE8-007B06CB07BB   # "de-swapped".

你似乎在你的流程中进行了64位单位内的字节交换。即使是字节数组也被反转,这表明它可能作为64位加载的一部分在某个地方加载,并且会受到swap64操作的影响。


我相信你所说的是正确的,因为我在32位边界上使用了swap64函数,所以64位int x = 0xAABBCCDD11223344 x swapped = 0x11223344AABBCCDD。然后将整个uuid视为4个32位int,我使用swap 32来得到:0x44332211DDCCBBAA。 - sebenalern
你的问题并没有提到swap64,哈哈。 - Kaz
我有一个函数库,所以我决定尝试在整个uuid上使用它,而不是每个字段。所以我基本上做了这样的事情:swap64along32(uuid); swap32(uuid); 我不确定为什么交换单独的字段没有起作用。我想你说的是对的。它把uuid当作两个64位整数来处理。 - sebenalern
既然你基本上引导我到那里了,如果你能在评论中总结一下我所做的事情,以便其他可能遇到类似问题的用户参考,我会接受你的答案。 - sebenalern

3

你尝试过访问单个字节吗?

uint8_t packet[4];
uint32_t value;
packet[0] = (value >> 24) & 0xFF;
packet[1] = (value >> 16) & 0xFF;
packet[2] = (value >>  8) & 0xFF;
packet[3] = value & 0xFF;

比调用函数更有效率。 :-)

注意:上述方法与平台无关。不需要了解value的存储方式。

解释:
假设packet是一个缓冲区或内存目标,需要将一个uint32_t以Big Endian格式(最高有效字节优先)存储到缓冲区中。

表达式(value >> 24)将最高有效字节移位到最低有效(字节)位置。表达式"& 0xff"截断任何多余的值,结果为一个无符号8位值。该值然后在缓冲区的第一个位置中以最高有效位置存储。

对于其余的字节也是如此。


我还没有尝试过这个。packet代表什么?抱歉,我不太明白这个。你能再详细解释一下吗? - sebenalern
Packet 表示您的目标数据包或缓冲区。 - Thomas Matthews
我还不确定UUID中的所有字节是否都必须交换,或者只需要交换我上面指定的字节。 - sebenalern
UUID的字节顺序取决于接收者或协议。提示:在互联网上搜索“UUID协议”。 - Thomas Matthews

0
推荐的方法是使用函数htonl(对于16位整数使用htons)将主机字节顺序转换为网络字节顺序,并使用ntohl(对于16位整数使用ntohs)将网络字节顺序转换为主机字节顺序。
给定以下结构:
struct UUID_FIELDS
{
    uint32_t time_low;                
    uint16_t time_mid;                 
    uint16_t time_hi_and_version;      
    uint8_t clock_seq_hi_and_reserved;
    uint8_t clock_seq_low;             
    uint8_t node[6];                   
};

序列化和反序列化的代码可能如下所示:

std::string serialize(UUID_FIELDS fields) {
    std::string buffer(sizeof(fields), '\0');

    // convert all fields with size > 1 byte to big endian (network byte order)
    fields.time_low = htonl(fields.time_low);
    fields.time_mid = htons(fields.time_mid);
    fields.time_hi_and_version = htons(fields.time_hi_and_version);

    memcpy(&buffer[0], &fields, sizeof(fields));

    return buffer;
}

UUID_FIELDS deserialize(const std::string& buffer) {
    UUID_FIELDS fields;

    assert(buffer.size() == sizeof(fields));

    memcpy(&fields, &buffer[0], sizeof(fields));

    // convert all fields with size > 1 byte to little endian (maybe) (host byte order)
    fields.time_low = ntohl(fields.time_low);
    fields.time_mid = ntohs(fields.time_mid);
    fields.time_hi_and_version = ntohs(fields.time_hi_and_version);

    return fields;
}

请注意,您必须与远程端点的接收方/发送方达成一致,以使用大端序发送/接收数字。

只有在主机是小端字节序的情况下,这才能正常工作。如果不是,它将不起任何作用。 - user207421
@EJP是的,你说得对,这里有一个链接引用了这个内容:https://beej.us/guide/bgnet/output/html/multipage/htonsman.html "这意味着在Intel上,这些函数会交换所有字节的顺序,在PowerPC上则不会,因为字节已经处于网络字节顺序。" - sebenalern
@EJP 这就是它应该工作的方式。如果主机字节顺序为小端,则交换位,如果主机字节顺序为大端,则不执行任何操作。也许您指的是另一个答案,其中字节始终被交换? - ichramm

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