用提升精神解析负十六进制值

时间:2016-11-07 20:15:54

标签: boost-spirit

为什么此代码无效

   std::string strVariant = "8000";
   short i16Value = 0;
   std::string::iterator it = strVariant.begin();
   if (qi::parse(it, strVariant.end(), qi::int_parser<short, 16>(), i16Value))
   {
      int a = 5;
   }

我希望值-32768。但解析失败,i16Value包含0x800。 我使用boost 1.56.00

2 个答案:

答案 0 :(得分:2)

这是在Spirit内部的溢出检查失败。要解决此问题,请使用uint_parser将signed short作为模板参数传递:

qi::uint_parser<short, 16>()

更新:从源代码中提取 提升1.60

spirit \ home \ qi \ numeric \ detail \ numeric_utils.hpp +142

inline static bool add(T& n, Char ch, mpl::true_) // checked add
{
    // Ensure n *= Radix will not overflow
    typedef constexpr_int<T, boost::integer_traits<T>::const_max> max;
    typedef constexpr_int<T, max::value / Radix> val;

    if (n > val::value)
        return false;

现在:

val::value = 32767/16 = 2047 
n = 2048 (0x800) // 3 chars parsed

答案 1 :(得分:1)

这是设计的。

与C ++文字一样,使用iostream或POSIX函数,根据定义,十六进制数字是无符号的。

如果需要,您必须简单地解析为无符号并转换为带符号的类型。

实际上,您可以通过将uint属性传递给简单的hexuint_parser<uint32_t, 16>来隐式转换它。

为了帮助处理属性强制规则,您可以通过指定“冲突”类型uint_parser<int32_t, 16>来让转换发生在int解析器本身。

当嵌入你的语法定义时,所有这些都非常微妙,所以我一定要添加一个简单的注释,如果只是为了防止人们“修复”这个bug:)

¹见例如sscanf with hexadecimal negative value