【问题标题】:Fast 64 bit comparison快速 64 位比较
【发布时间】:2011-01-22 18:53:19
【问题描述】:

我正在开发一个 GUI 框架,我希望所有元素都由最多 8 个字符的 ascii 字符串标识(或者 7 个就可以了)。

每次触发事件时(有些只是点击,但有些是连续的),框架会用 id 及其值回调到客户端代码。

我可以使用实际的字符串和 strcmp(),但我希望它非常快(对于移动设备),所以我想使用 char 常量(例如 int id = 'BTN1';)所以你会做一个单一的int比较来测试id。但是,4 个字符的可读性不够。

我尝试了一个实验,比如—— long int id = L'abcdefg';

...但看起来 char 常量只能容纳 4 个字符,而制作 long int char 常量的唯一方法是让您的 4 个字符宽两倍,而不是两倍人物。我在这里遗漏了什么吗?

我想让编写客户端代码的人更容易。 gui 存储在 xml 中,因此 id 是从字符串中加载的,但是客户端代码中会写入常量来比较它们。

所以,总而言之,我正在寻找一种跨平台的方法来快速进行 7-8 字符比较,有什么想法吗?

【问题讨论】:

  • 每秒进行多少次比较?不用出汗,用绳子就够快了。
  • 如果您的目标是为组件提供命名方案,请不要使用 long-char 的 ascii。
  • 这可能是不可移植的。根据 C++ 标准,多字符文字(在 's 之间的多个字符)的值是实现定义的。检查您的实现文档以查看它是否正在执行您想要的操作,并检查所有可用于查看它们都执行相同操作的实现。
  • 你说得对,Pop 和 Hassan,我想这不会影响性能,并且从一开始就限制了 64 位字符串。会用字符串。

标签: c++ string comparison


【解决方案1】:

您确定这不是过早的优化吗?您是否分析过另一个纯粹来自字符串比较的缓慢 GUI 框架?你为什么这么肯定字符串比较会太慢?当然,您没有进行 that 很多字符串比较。另外,考虑 strcmp 应该有一个接近最优的实现,可能是用为你正在编译的 CPU 量身定制的汇编编写的。

反正其他框架只是使用命名整数,例如:

static const int MY_BUTTON_ID = 1;

您可以考虑这样做,完全避免字符串问题。或者,您可以简单地编写一个辅助函数来将 const char[9] 转换为 64 位整数。这应该接受一个以 null 结尾的字符串“like so”,最多 8 个字符(假设您打算丢弃 null 字符)。那么你的程序正在传递大约 64 位整数,但程序员正在处理字符串。

编辑:这是一个将字符串转换为数字的快速函数:

__int64 makeid(const char* str)
{
    __int64 ret = 0;
    strncpy((char*)&ret, str, sizeof(__int64));
    return ret;
}

【讨论】:

  • 我见过很多 gui 框架使用 int id,但是由于我的框架是基于接口构建器的,编码器必须将数字复制到他们的代码中(不优雅)或者接口构建器的必须为每个元素生成一个带有定义的头文件,这不适用于框架的某些应用程序我认为你是完全正确的,我没有做那么多比较,所以我会坚持字符串。我确信我的代码中的其他地方会有更大的瓶颈!谢谢!
  • 如果您要坚持使用字符串,而且其他人已经花时间回答您的具体问题,为什么要选择这个答案? ?
  • 也许你没有得到我答案的最后一部分,所以我编辑了一个函数来显示。如果你调用 makeid("my id") 你会得到一个 __int64 并将字符串复制到其中。这允许您在程序员输入字符串的便利的情况下进行整数比较。请注意,它会忽略 8 号之后的所有字符。
  • 啊,谢谢阿什利。我想 Ashley 让我更清楚地知道 strncmp 惩罚不太可能给我带来如此大的性能影响。该解决方案需要在性能和简洁性/可读性之间取得良好的折衷。我刚刚在 OS X 上做了一个基本的速度测试,无论成功还是失败,strcmp 似乎都比内联 makeid() 快 8-9 倍。无论如何,它每秒都在做几亿次。 (Ashley 你能把你的帖子编辑成 strncpy((char*)&ret, ...) 干杯!)
  • 我没想到速度差异会是 8-9 倍,但如果你测量它,就足够公平了。修正了语法错误,干杯。
【解决方案2】:

一种可能性是将您的 ID 定义为 64 位整数和 8 个字符的字符串的联合:

union ID {
  Int64 id;      // Assuming Int64 is an appropriate typedef somewhere
  char name[8];
};

现在您可以执行以下操作:

ID id;
strncpy(id.name, "Button1", 8);
if (anotherId.id == id.id) ...

【讨论】:

    【解决方案3】:

    string interning 的概念可以解决这个问题,将字符串比较转换为指针比较。

    【讨论】:

    • 我喜欢只比较指针的想法,但我试图获得一个对于编码员的观点来说也是最佳的解决方案(也许我不能两全其美),例如void controlClicked(sometype id, void *value) { if(id==SOME_MACRO('myButton')) { doSomethingWith(value); } else if(id==SOME_MACRO('mySlider')) { doSomethingElse(value);在这样的代码中,使用文字“myButton”和“mySlider”,程序员可以编写更少的代码。也许我可以把 SOME_MACRO() 变成一个散列函数......
    【解决方案4】:

    易于获得预卷组件

    binary search tree 获胜——您从 set 和 map 的大多数 STL 实现中获得 red-black 树,因此您可能需要考虑这一点。

    Intrusive versions 的 STL 容器在您大量移动容器节点(在一般情况下)时性能要好得多 - 但是它们有很多警告。

    具体意见 -- 第一种选择

    如果我是你,我会坚持使用 64 位整数类型并将其捆绑在一个侵入式容器中,并使用 boost 提供的库。但是,如果您不熟悉这类东西,那么使用 stl::map 从概念上讲更容易掌握,并且由于有更多关于这些类型的容器和最佳实践的文献和指南,因此泄漏资源的机会也更少。

    备选方案 2

    我相信您要解决的问题是:拥有一个映射到句柄的全局命名方案。您可以创建名称到句柄的映射,以便您可以使用名称来检索句柄:

    // WidgetHandle is a polymorphic base class (i.e., it has a virtual method),
    // and foo::Luv implement WidgetHandle's interface (public inheritance)
    foo::WidgetHandle * LuvComponent = 
              Factory.CreateComponent<foo::Luv>( "meLuvYouLongTime");
    ....
    
    .... // in different function
    foo::WidgetHandle * LuvComponent = 
              Factory.RetrieveComponent<foo::Luv>("meLuvYouLongTime");
    

    Alternative 2 是 IPC 的一个常见习惯用法,您可以在一个进程中创建一个 IPC 类型,例如管道,然后您可以要求内核按名称检索管道的另一端。

    【讨论】:

    • 感谢您的回答。我想我正在寻找最少的 LOC 版本,对程序员来说最少的麻烦,同时试图让它尽可能快。我已经对它的组件检索部分进行了排序,它只是在确定事件来自哪个组件。
    【解决方案5】:

    我发现代码中易于阅读的标识符与传递的表示之间存在区别。

    您可以使用枚举类型(或大型常量头文件)来表示标识符吗?枚举类型的名称可以随心所欲地长且有意义,并且仍然适合(我猜)几个字节。

    【讨论】:

      【解决方案6】:

      在 C++0x 中,您将能够使用 user-defined string literals,因此您可以添加类似 7chars..id"7chars.."id 的内容:

      template <char...> constexpr unsigned long long operator ""id();
      constexpr unsigned long long operator ""id(const char *, size_t);
      

      虽然我不确定你是否可以将constexpr 用于第二个。

      【讨论】:

        猜你喜欢
        • 2023-03-07
        • 2021-02-07
        • 2011-10-02
        • 1970-01-01
        • 2014-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多