C ++中的GUID常量(特定于Orwell Dev-C ++)

时间:2015-09-23 17:01:03

标签: c++ guid

我正在将很多插件从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} };

这很烦人,因为有两件事:

  1. 我很难翻译,因为我需要手工分割我的GUID,并且存在我犯错误的风险(因此提供错误的GUID)。

  2. 由于源是公开的,我确实希望人们使用人类可读的GUID,例如用它来研究网络等 所以我需要在常量上面添加注释:

    // {6C26245E-F79A-416C-8C73-BEA3EC18BB6E}
    static const GUID GUID_PLUGIN_ABC_V1 =
      {0x6C26245E, 0xF79A, 0x416C, { 0x8C, 0x73, 0xBE, 0xA3, 0xEC, 0x18, 0xBB, 0x6E} };
    
  3. 现在我有以下问题:

    1. 此任务是否有良好的转换器(对于现有的GUID)?
    2. 是否有一种工具可以创建新的GUID以此常量表示法?
    3. 我是否有可能使用宏,例如

      static const GUID GUID_PLUGIN_ABC_V1 =
        GUIDMACRO('{6C26245E-F79A-416C-8C73-BEA3EC18BB6E}')
      

    4. GUID与COM无关。

2 个答案:

答案 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格式进行一些不同的搜索和替换字符串。