我正在将很多插件从Delphi翻译成C ++,每个插件都由GUID标识。
在Delphi中,这个常量看起来很不错:
const
GUID_PLUGIN_ABC_V1: TGUID = '{6C26245E-F79A-416C-8C73-BEA3EC18BB6E}';
在我的C ++翻译中,我需要做以下事情:
static const GUID GUID_PLUGIN_ABC_V1 =
{0x6C26245E, 0xF79A, 0x416C, { 0x8C, 0x73, 0xBE, 0xA3, 0xEC, 0x18, 0xBB, 0x6E} };
这很烦人,因为有两件事:
我很难翻译,因为我需要手工分割我的GUID,并且存在我犯错误的风险(因此提供错误的GUID)。
由于源是公开的,我确实希望人们使用人类可读的GUID,例如用它来研究网络等 所以我需要在常量上面添加注释:
// {6C26245E-F79A-416C-8C73-BEA3EC18BB6E}
static const GUID GUID_PLUGIN_ABC_V1 =
{0x6C26245E, 0xF79A, 0x416C, { 0x8C, 0x73, 0xBE, 0xA3, 0xEC, 0x18, 0xBB, 0x6E} };
现在我有以下问题:
我是否有可能使用宏,例如
static const GUID GUID_PLUGIN_ABC_V1 =
GUIDMACRO('{6C26245E-F79A-416C-8C73-BEA3EC18BB6E}')
GUID与COM无关。
答案 0 :(得分:2)
您可以使用用户定义的文字:
#include <array>
#include <cstring>
#include <iostream>
struct Guid
{
uint32_t a = 0;
uint16_t b = 0;
uint16_t c = 0;
uint16_t d = 0;
std::array<uint8_t, 6> e;
};
Guid operator "" _guid (const char* s, std::size_t n)
{
if(n == 38)
{
// Parse and consider byte order (endian).
// Provide something reasonable to replace this:
if(std::strncmp(s, "{6C26245E-F79A-416C-8C73-BEA3EC18BB6E}", 36) == 0)
{
Guid result;
result.a = 0x6C26245E;
result.b = 0xF79A;
result.c = 0x416C;
result.d = 0x8C73;
result.e = { 0xBE, 0xA3, 0xEC, 0x18, 0xBB, 0x6E };
return result;
}
}
// Invalid
return Guid();
}
int main()
{
Guid guid = "{6C26245E-F79A-416C-8C73-BEA3EC18BB6E}"_guid;
std::cout << std::hex
<< guid.a << "-"
<< guid.b << "-"
<< guid.c << "-"
<< guid.d << "-"
<< "array\n";
}
请参阅http://en.cppreference.com/w/cpp/language/user_literal
编辑:解析
#include <array>
#include <cctype>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#pragma pack(push, 0)
struct Guid
{
std::uint32_t data1;
std::uint16_t data2;
std::uint16_t data3;
std::array<uint8_t, 8> data4;
};
#pragma pack(pop)
// A guid with the format "01234567-89ab-cdef-0123-456789abcdef"
// If the guid string is invalid the resulting guid is an empty guid.
// Note: The first three fields of the guid are stored in a host byte order.
// and the last two fields are stored in a single array (big endian)
Guid operator "" _guid (const char* s, std::size_t n)
{
// Hexadecimal character test.
struct IsXDigit
{
bool result = true;
IsXDigit(const char*& p, unsigned n)
{
while(n--) {
char c = *p++;
// char may be signed or unsigned
if(c < 0 || 128 <= c || ! std::isxdigit(c)) {
result = false;
break;
}
}
}
operator bool () const { return result; }
};
Guid result;
// Syntax
const char* p = s;
if( ! IsXDigit(p, 8)) goto Failure;
if(*p++ != '-') goto Failure;
if( ! IsXDigit(p, 4)) goto Failure;
if(*p++ != '-') goto Failure;
if( ! IsXDigit(p, 4)) goto Failure;
if(*p++ != '-') goto Failure;
if( ! IsXDigit(p, 4)) goto Failure;
if(*p++ != '-') goto Failure;
if( ! IsXDigit(p, 12)) goto Failure;
if(*p) goto Failure;
// Data
result.data1 = std::uint32_t(std::strtoul(s, nullptr, 16));
result.data2 = std::uint16_t(std::strtoul(s + 9, nullptr, 16));
result.data3 = std::uint16_t(std::strtoul(s + 14, nullptr, 16));
char buffer[3];
buffer[2] = 0;
for(unsigned dst = 0, src = 19; src < 23; ++dst, src += 2)
{
buffer[0] = s[src];
buffer[1] = s[src + 1];
result.data4[dst] = std::uint8_t(std::strtoul(buffer, nullptr, 16));
}
for(unsigned dst = 2, src = 24; src < 36; ++dst, src += 2)
{
buffer[0] = s[src];
buffer[1] = s[src + 1];
result.data4[dst] = std::uint8_t(std::strtoul(buffer, nullptr, 16));
}
return result;
Failure:
std::memset(&result, 0, sizeof(result));
return result;
}
#include <iostream>
#include <iomanip>
int main()
{
const Guid guid = "6C26245E-F79A-416C-8C73-BEA3EC18BB6E"_guid;
std::cout.fill('0');
std::cout
<< std::hex
<< "6C26245E-F79A-416C-8C73-BEA3EC18BB6E\n"
<< std::setw(8) << guid.data1 << "-"
<< std::setw(4) << guid.data2 << "-"
<< std::setw(4) << guid.data3 << "-";
for(unsigned i = 0; i < 2; ++i)
std::cout << std::setw(2) << unsigned(guid.data4[i]);
std::cout << "-";
for(unsigned i = 2; i < 8; ++i)
std::cout << std::setw(2) << unsigned(guid.data4[i]);
std::cout << '\n';
}
答案 1 :(得分:0)
由于您只是以不同的格式从文本转换为文本,因此正则表达式查找和替换将很有用。以下是在Notepad ++中开发和测试的。不同的编辑器(如Visual Studio)可能有不同的正则表达式规则,但基础知识将是相同的。
搜索:
const ([\w]+)\: TGUID = '\{(.{8})-(.{4})-(.{4})-(..)(..)-(..)(..)(..)(..)(..)(..)\}';
替换为:
static const GUID $1 = {0x$2, 0x$3, 0x$4, { 0x$5, 0x$6, 0x$7, 0x$8, 0x$9, 0x$10, 0x$11, 0x$12} };
我无法解释有关使用正则表达式搜索的所有细节,但基本要理解的是搜索字符串中的括号“捕获”该行的匹配区域,并在替换字符串$ 1,$ 2等中插入什么被捕获。
例如,第一组括号为([\w]+)
。这用于捕获GUID的名称(示例中为GUID_PLUGIN_ABC_V1
)。要将其细分,[\w]
说“匹配所有单词字符”,+
表示“匹配一个或多个前面的字符”。括号捕获它,$ 1将名称添加到替换字符串。群组(.{8})
是“匹配任何角色8次”而(..)
是猪鼻子......但严重的是,.
表示“任何角色”,所以(..)
只是匹配两个字符。
请注意,此正则表达式查找和替换选项假定所有传入的GUID字符串都有效,并遵循以下形式:
const <GUID NAME>: TGUID = '{<GUID STRING>}';
如果有任何变化,正则表达式的轻微更改可以解释它们。最糟糕的情况是,您可以根据各种GUID格式进行一些不同的搜索和替换字符串。