C++ 从无符号字符数组创建 GUID
C++ Creating GUID from unsigned char array
我有一个函数,它将一个无符号字符数组(恰好 16 个值)作为输入,并通过将所有值解析为十六进制并将 guid 格式的字符串传递给 [=12= 创建一个 GUID(来自 GUID 结构) ].
我的代码如下:
GUID CreateGuid(const uint8_t* data)
{
createGuidFromBufferData(hexValues, data);
int uuidCreationReturnCode = UuidFromStringA((RPC_CSTR)hexValues, &guid);
return guid;
}
inline void createGuidFromBufferData(char* hexValues, const uint8_t* data)
{
decimalToHexadecimal(data[3], hexValues, 0);
decimalToHexadecimal(data[2], hexValues, 2);
decimalToHexadecimal(data[1], hexValues, 4);
decimalToHexadecimal(data[0], hexValues, 6);
hexValues[8] = '-';
decimalToHexadecimal(data[5], hexValues, 9);
decimalToHexadecimal(data[4], hexValues, 11);
hexValues[13] = '-';
decimalToHexadecimal(data[6], hexValues, 14);
decimalToHexadecimal(data[7], hexValues, 16);
hexValues[18] = '-';
decimalToHexadecimal(data[8], hexValues, 19);
decimalToHexadecimal(data[9], hexValues, 21);
hexValues[23] = '-';
decimalToHexadecimal(data[10], hexValues, 24);
decimalToHexadecimal(data[11], hexValues, 26);
decimalToHexadecimal(data[12], hexValues, 28);
decimalToHexadecimal(data[13], hexValues, 30);
decimalToHexadecimal(data[14], hexValues, 32);
decimalToHexadecimal(data[15], hexValues, 34);
}
inline void decimalToHexadecimal(uint8_t decimalValue, char* outputBuffer, int currentIndex)
{
const char hexValues[] = "0123456789abcdef";
outputBuffer[currentIndex] = hexValues[decimalValue >> 4];
outputBuffer[currentIndex + 1] = hexValues[decimalValue & 0xf];
}
这工作正常,但我想做一些更有效率的事情,并使用我的输入字符数组直接创建 GUID,如下所示:
GUID CreateGuid(const uint8_t* data)
{
GUID guid = {
*reinterpret_cast<const unsigned long*>(data),
*reinterpret_cast<const unsigned short*>(data + 4),
*reinterpret_cast<const unsigned short*>(data + 6),
*reinterpret_cast<const unsigned char*>(data + 8)
};
return guid;
}
这样做时,最后8个字节只有一个被设置,其余为0;
例如使用无符号字符数组
[38, 150, 233, 16, 43, 188, 117, 76,
187, 62, 254, 96, 109, 226, 87, 0]
我什么时候应该得到:
10e99626-bc2b-754c-bb3e-fe606de25700
我得到的是:
10e99626-bc2b-75dc-bb00-000000000000}
您不能像您尝试的那样简单地通过取消引用指向源数据的强制转换指针并将该值分配给它的第一个元素来填充 8 字符数组。正如您所注意到的,这样做只会为第一个元素赋值。
对于GUID
结构末尾的8字符数组,可以单独初始化每个元素,扩展cast + offset方法:
GUID CreateGuid(const uint8_t* data)
{
GUID guid = {
*reinterpret_cast<const unsigned long*>(data),
*reinterpret_cast<const unsigned short*>(data + 4),
*reinterpret_cast<const unsigned short*>(data + 6),
{ // We need to assign each of the 8 elements of the array ...
*reinterpret_cast<const unsigned char*>(data + 8),
*reinterpret_cast<const unsigned char*>(data + 9),
*reinterpret_cast<const unsigned char*>(data + 10),
*reinterpret_cast<const unsigned char*>(data + 11),
*reinterpret_cast<const unsigned char*>(data + 12),
*reinterpret_cast<const unsigned char*>(data + 13),
*reinterpret_cast<const unsigned char*>(data + 14),
*reinterpret_cast<const unsigned char*>(data + 15),
}
};
return guid;
}
注意: 正如评论中指出的(谢谢,Timo), using this direct initialization approach risks invoking undefined behaviour, especially if the passed source data buffer isn't suitably aligned for the corresponding destination types, because of the Strict Aliasing Rule。为避免这种情况,您应该使用 memcpy
从源传输数据缓冲区到目标结构的元素:
GUID CreateGuid(const uint8_t* data)
{
GUID guid;
std::memcpy(&guid.Data1, data, sizeof(long));
std::memcpy(&guid.Data2, data + 4, sizeof(short));
std::memcpy(&guid.Data3, data + 6, sizeof(short));
std::memcpy(guid.Data4, data + 8, 8); // sizeof(char) == 1
return guid;
}
此外,由于 GUID
结构的定义方式 应该 在其元素之间不添加填充字节,您可以将数据复制到一个一举成名:
GUID CreateGuid(const uint8_t* data)
{
GUID guid;
std::memcpy(&guid, data, sizeof(GUID)); // Assuming no padding!
return guid;
}
GUID
是一个具有简单复制分配的聚合。因此,您应该能够直接执行此操作。
GUID CreateGuid(const uint8_t* data)
{
return *reinterpret_cast<GUID*>(data)
}
我有一个函数,它将一个无符号字符数组(恰好 16 个值)作为输入,并通过将所有值解析为十六进制并将 guid 格式的字符串传递给 [=12= 创建一个 GUID(来自 GUID 结构) ].
我的代码如下:
GUID CreateGuid(const uint8_t* data)
{
createGuidFromBufferData(hexValues, data);
int uuidCreationReturnCode = UuidFromStringA((RPC_CSTR)hexValues, &guid);
return guid;
}
inline void createGuidFromBufferData(char* hexValues, const uint8_t* data)
{
decimalToHexadecimal(data[3], hexValues, 0);
decimalToHexadecimal(data[2], hexValues, 2);
decimalToHexadecimal(data[1], hexValues, 4);
decimalToHexadecimal(data[0], hexValues, 6);
hexValues[8] = '-';
decimalToHexadecimal(data[5], hexValues, 9);
decimalToHexadecimal(data[4], hexValues, 11);
hexValues[13] = '-';
decimalToHexadecimal(data[6], hexValues, 14);
decimalToHexadecimal(data[7], hexValues, 16);
hexValues[18] = '-';
decimalToHexadecimal(data[8], hexValues, 19);
decimalToHexadecimal(data[9], hexValues, 21);
hexValues[23] = '-';
decimalToHexadecimal(data[10], hexValues, 24);
decimalToHexadecimal(data[11], hexValues, 26);
decimalToHexadecimal(data[12], hexValues, 28);
decimalToHexadecimal(data[13], hexValues, 30);
decimalToHexadecimal(data[14], hexValues, 32);
decimalToHexadecimal(data[15], hexValues, 34);
}
inline void decimalToHexadecimal(uint8_t decimalValue, char* outputBuffer, int currentIndex)
{
const char hexValues[] = "0123456789abcdef";
outputBuffer[currentIndex] = hexValues[decimalValue >> 4];
outputBuffer[currentIndex + 1] = hexValues[decimalValue & 0xf];
}
这工作正常,但我想做一些更有效率的事情,并使用我的输入字符数组直接创建 GUID,如下所示:
GUID CreateGuid(const uint8_t* data)
{
GUID guid = {
*reinterpret_cast<const unsigned long*>(data),
*reinterpret_cast<const unsigned short*>(data + 4),
*reinterpret_cast<const unsigned short*>(data + 6),
*reinterpret_cast<const unsigned char*>(data + 8)
};
return guid;
}
这样做时,最后8个字节只有一个被设置,其余为0; 例如使用无符号字符数组 [38, 150, 233, 16, 43, 188, 117, 76, 187, 62, 254, 96, 109, 226, 87, 0]
我什么时候应该得到:
10e99626-bc2b-754c-bb3e-fe606de25700
我得到的是:
10e99626-bc2b-75dc-bb00-000000000000}
您不能像您尝试的那样简单地通过取消引用指向源数据的强制转换指针并将该值分配给它的第一个元素来填充 8 字符数组。正如您所注意到的,这样做只会为第一个元素赋值。
对于GUID
结构末尾的8字符数组,可以单独初始化每个元素,扩展cast + offset方法:
GUID CreateGuid(const uint8_t* data)
{
GUID guid = {
*reinterpret_cast<const unsigned long*>(data),
*reinterpret_cast<const unsigned short*>(data + 4),
*reinterpret_cast<const unsigned short*>(data + 6),
{ // We need to assign each of the 8 elements of the array ...
*reinterpret_cast<const unsigned char*>(data + 8),
*reinterpret_cast<const unsigned char*>(data + 9),
*reinterpret_cast<const unsigned char*>(data + 10),
*reinterpret_cast<const unsigned char*>(data + 11),
*reinterpret_cast<const unsigned char*>(data + 12),
*reinterpret_cast<const unsigned char*>(data + 13),
*reinterpret_cast<const unsigned char*>(data + 14),
*reinterpret_cast<const unsigned char*>(data + 15),
}
};
return guid;
}
注意: 正如评论中指出的(谢谢,Timo), using this direct initialization approach risks invoking undefined behaviour, especially if the passed source data buffer isn't suitably aligned for the corresponding destination types, because of the Strict Aliasing Rule。为避免这种情况,您应该使用 memcpy
从源传输数据缓冲区到目标结构的元素:
GUID CreateGuid(const uint8_t* data)
{
GUID guid;
std::memcpy(&guid.Data1, data, sizeof(long));
std::memcpy(&guid.Data2, data + 4, sizeof(short));
std::memcpy(&guid.Data3, data + 6, sizeof(short));
std::memcpy(guid.Data4, data + 8, 8); // sizeof(char) == 1
return guid;
}
此外,由于 GUID
结构的定义方式 应该 在其元素之间不添加填充字节,您可以将数据复制到一个一举成名:
GUID CreateGuid(const uint8_t* data)
{
GUID guid;
std::memcpy(&guid, data, sizeof(GUID)); // Assuming no padding!
return guid;
}
GUID
是一个具有简单复制分配的聚合。因此,您应该能够直接执行此操作。
GUID CreateGuid(const uint8_t* data)
{
return *reinterpret_cast<GUID*>(data)
}