简体   繁体   中英

How to convert UUID to big endian?

My UUID is structured like this:

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];                   

};

I have functions that swap along 32 bit boundaries and a swap function that swaps along 16 bit boundaries. I have tried calling swap32() on time_low and swap16() on time_mid and time_hi_and_version . I do not believe I need to swap bytes for the rest of the fields because two of them are 8 bit fields and I have read that the node part of a uuid does not change. Here is a link for that reference.

The problem is when I complete the swaps the uuid that is printed does not match the one that was in little endian before being converted.

What is the correct way to convert a uuid following RFC-4122 standard from little endian to big endian . And when converted should the uuids match?

Re:

Update: Starting uuid in little endian:

 446831D3-FBA1-477B-BB07-CB067B00E86B 

Result from correctly swapping necessary fields:

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

This looks horribly wrong. We can deduce that if the swaps are correct and affect only the 32 and 16 bit fields, then without swapping the necessary fields, it would be this:

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

What you seem to have have going on here is byte swapping within 64 bit units somewhere in your pipeline. Even the array of bytes is being reversed, suggesting that it might be loaded somewhere as part of a 64 bit load, which is subject to a swap64 operation.

Have you tried accessing the individual bytes?

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;

Probably more efficient than calling a function. :-)

Note: the above method is platform independent. Doesn't require any knowledge how the value is stored.

Explanation:
Let packet be a buffer or memory destination for a uint32_t that needs to be stored into the buffer in Big Endian format (Most Significant Byte First).

The expression ( value >> 24 ) shifts the most significant byte to the least significant (byte) position. The expression "& 0xff" truncates, chops off, any extraneous values, resulting in an unsigned 8-bit value. The value is then stored in the Most Significant position in the buffer at the first location.

Likewise for the remaining bytes.

The recommended way is to use the function htonl ( htons for 16 bit integers) to convert from host byte order to network byte order, and ntohl ( ntohs for 16 bit integers) to convert from network byte order to host byte order

Given the following structure:

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];                   
};

The code for serialization and deserialization might be as follows:

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;
}

Note that you have to agree with the receiver/sender in the remote endpoint that you are both sending/receiving numbers in big endian.

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