【问题标题】:What is the most efficient way to convert a short string into a 32 bit integer?将短字符串转换为 32 位整数的最有效方法是什么?
【发布时间】:2018-06-05 16:39:32
【问题描述】:

出于许多目的,打包成无符号 32 位整数的短字符串/字符数组非常有用,因为它们可以通过简单的整数比较一次性进行比较,并可用于switch 语句,同时仍保持有点人类可读性。

将这些短字符串转换为 32 位整数的最常用方法是移位/或:

#include <stdint.h>

uint32_t quadchar( const char* _str ) 
{

    uint32_t result = 0;

    for( size_t i=0; i<4; i++ )
    {
        if( _str[i] == 0 )
           return result;
        result = (result << 8) | _str[i];
    }

    return result;
}

过长的字符串会被截断。

到目前为止一切顺利,但这必须在运行时完成,这会花费一些时间。 是否也可以在编译时执行此操作?

【问题讨论】:

  • 使用 C++14 及更高版本,您只需将 constexpr 添加到您的函数中。已经有一个答案显示如何为 C++11 执行此操作(即递归)。对于 C++03,几乎不可能获得良好的语法,但 C++03 的一个解决方案是通过一些脚本对源代码进行预处理。
  • 联合方法将是未定义的行为,结果取决于 CPU 的字节序。
  • @Barmar:真的,谢谢。我删除了这段话。

标签: c++ string c++11 integer constexpr


【解决方案1】:

不需要详细帮助函数:您可以使用默认值。

并且不需要双三元运算符:您可以通过一次测试完成所有操作

std::uint32_t inline constexpr quadchar (char const * input, 
                                         std::size_t idx = 0U,
                                         std::uint32_t result = 0U) 
 {
   return (idx < 4U) && *input
      ? quadchar(input+1, idx+1U, (result << 8) | *input)
      : result;
 }

但是,为了让它更便携和通用,我建议

1) 使用sizeof() 而不是4 来限制idx

2) 使用CHAR_BIT 代替8 进行result 班次(记得包含“&lt;climits&gt;”)

3) 为result 类型使用模板类型(如果需要,默认为std::uint32_t)。

类似

template <typename I = std::uint32_t>
constexpr inline I ichar (char const * input, 
                          I result = 0U,
                          std::size_t idx = 0U)
 {
   return (idx < sizeof(I)) && *input
      ? ichar(input+1, idx+1U, (result << CHAR_BIT) | *input)
      : result;
 }

你可以打电话

constexpr auto u32 = ichar(ptr);

当你想要 std::uint32_t 时,或(例如)

constexpr auto u64 = ichar<std::uint64_t>(ptr);

对于其他返回的类型。

【讨论】:

  • 谢谢。 sizeof() 和模板的想法非常好。我不太确定CHAR_BIT。在CHAR_BIT != 8 的情况下,由于移位不同,结果将与 8 位字符的结果不同;我认为这是不那么便携而不是更多。使用输入字符代替额外的&amp; 0xff 可能会更好。辅助函数的实现是为了隐藏result 和input 参数,因为它们对用户没有意义。不过当然默认参数也可以。
  • @user2328447 - 我也对CHAR_BIT 有一些疑问(例如:std::uint32_t 存在于具有CHAR_BIT = 12 的平台中?)但如果CHAR_BIT &gt; 8 (@987654345 @ 是最小值),input 中的每个字符都带有 CHAR_BIT 位;因此,对于(result &lt;&lt; 8) | *input,您在前一个字符中的最后一位和*input 中的第一个位发生冲突(或位)。
  • @user2328447 - 是的:&amp; 0xff 想法可能是一个很好的替代解决方案;考虑一下,这样一来,您就可以放弃使用字符中的某些位(以防CHAR_BITS &gt; 8)并管理input 字符中的正确位可能很困难并且取决于平台。
【解决方案2】:

从 C++11 开始,可以使用 constexpr specifier 在编译时以零成本在运行时执行此操作。

namespace Internal 
{
    uint32_t inline constexpr quadchar( char const *_input, 
        uint8_t _idx, uint32_t _result ) 
    {
        return _idx == 4 ? _result 
            : *_input ? quadchar ( _input+1, _idx + 1, (_result << 8) | *_input ) 
                : _result;
    }
}

uint32_t inline constexpr quadchar( char const *_input ) {
    return Internal::quadchar( _input, 0, 0 );
}

我已将实现重载放置到内部命名空间中以对用户隐藏它。语法不如上面的运行时示例好,因为你不能在constexpr 中使用if,但我认为这是值得的。

【讨论】:

  • 适用于该问题的相同可移植性警告也适用于此答案。可能如果转换后的字符串从未在网络上保存或发送,那也没关系。在这里致电honl() 可能是明智的。在许多 CPU 上编译成很少的指令 - 可能只有一个。
  • 对不起,我不太明白你的意思。这里有什么不便携的?据我所知,一切都应该是可移植的,并且不依赖于字节序。请问honl() 是什么?找不到任何相关信息。
猜你喜欢
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 2014-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多