RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1390616
Accepted
maestro
maestro
Asked:2022-08-16 11:01:31 +0000 UTC2022-08-16 11:01:31 +0000 UTC 2022-08-16 11:01:31 +0000 UTC

识别非 0 终止字符串中的数字

  • 772

有一个字符串表示为一对迭代器或一个指针char和一个长度。这条线的特殊之处在于它

  • 可能包含一个数字,但只有一个;
  • 可能包含错误值(额外字符或溢出的数字);
  • 可能什么都没有(begin+1 = end)。

我所知道的 C 和 C++ 标准库函数atoi,需要一个以 null 结尾std::stoi的sscanf字符串。C 和 C++ 库中是否有类似的标准函数?这些功能还需要:

  • 该函数不得在堆上动态分配内存;
  • 该函数不得使用 VLA;
  • 该函数不得抛出异常。

虽然声明 IAR EWARM 8.40.1 支持 C++17,但它不std::string_view包含std::from_chars. 后者看起来是最合适的,尽管它没有写任何地方是否在堆上分配内存以满足内部需求。

c++
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Stanislav Volodarskiy
    2022-08-16T22:53:31Z2022-08-16T22:53:31Z

    在“复杂”的操作中,需要乘以十,可以用三班一加代替:

    #include <assert.h>
    #include <ctype.h>
    #include <limits.h>
    #include <stdbool.h>
    
    bool parse_uint(int n, const char s[/* n */], unsigned *result) {
        if (n <= 0) {
            return false;
        }
        unsigned r = 0;
        for (const char *p = s; p < s + n; ++p) {
            if (!isdigit((unsigned char)*p)) {
                return false;
            }
            if (r > UINT_MAX / 10u) {
                return false;
            }
            r *= 10u;
            const unsigned d = *p - '0';
            if (r > UINT_MAX - d) {
                return false;
            }
            r += d;
        }
        *result = r;
        return true;
    }
    
    int main()
    {
        unsigned n;
        assert(parse_uint(1, "0", &n));
        assert(n == 0);
        assert(parse_uint(1, "1", &n));
        assert(n == 1);
        assert(parse_uint(2, "10", &n));
        assert(n == 10);
        assert(parse_uint(10, "4294967295", &n));
        assert(n == 4294967295);
        assert(!parse_uint(10, "4294967296", &n));
        assert(!parse_uint(11, "42949672950", &n));
        assert(!parse_uint(3, "1_2", &n));
        assert(!parse_uint(0, "0", &n));
        return 0;
    }
    
    • 3
  2. Qwertiy
    2022-08-16T23:29:10Z2022-08-16T23:29:10Z

    ⚠️ 显然,这个解决方案假设在没有 UB 的情况下可读的区域中仍然存在终止 0,但不一定紧跟在子字符串的结尾之后。

    答案的评论中有更多详细信息。

    sscanf可以做任何事情(顺便说一下,我没有检查 int 溢出):操场

    #include <cstdio>
    #include <iostream>
    
    using namespace std;
    
    void f(const char *s, const char *e)
    {
      int n = e-s-1;
    
      if (n >= 0)
        printf("'%.*s' (len %d) - ", n, s, n);
      else
        printf("(len %d) - ", n);
    
      if (n < 0)
        puts("invalid arguments");
      else if (!n)
        puts("empty input");
      else
      {
        char format[32];
        sprintf(format, "%%%dd%%n", n);
        int x, m;
        sscanf(s, format, &x, &(m=0));
    
        if (n != m)
          puts("invalid input");
        else
          printf("parsed as %d\n", x);
      }
    }
    
    int main()
    {
      const char *s = "-12345-67890123456789";
    
      f(s, s);
    
      f(s, s+1);
      f(s, s+2);
      f(s, s+7);
      f(s, s+8);
      f(s, s+10);
    
      f(s+1, s+2);
      f(s+1, s+3);
      f(s+1, s+7);
      f(s+1, s+8);
      f(s+1, s+10);
    
      f(s+6, s+17);
      f(s+6, s+18);
      f(s+7, s+17);
      f(s+7, s+18);
    
      f(s+18, s+20);
      f(s+18, s+21);
      f(s+18, s+22);
      f(s+18, s+23);
      f(s+18, s+100000);
    }
    
    (len -1) - invalid arguments
    '' (len 0) - empty input
    '-' (len 1) - invalid input
    '-12345' (len 6) - parsed as -12345
    '-12345-' (len 7) - invalid input
    '-12345-67' (len 9) - invalid input
    '' (len 0) - empty input
    '1' (len 1) - parsed as 1
    '12345' (len 5) - parsed as 12345
    '12345-' (len 6) - invalid input
    '12345-67' (len 8) - invalid input
    '-678901234' (len 10) - parsed as -678901234
    '-6789012345' (len 11) - parsed as 1800922247
    '678901234' (len 9) - parsed as 678901234
    '6789012345' (len 10) - parsed as -1800922247
    '7' (len 1) - parsed as 7
    '78' (len 2) - parsed as 78
    '789' (len 3) - parsed as 789
    '789' (len 4) - invalid input
    '789' (len 99981) - invalid input
    
    • 0
  3. maestro
    2022-08-16T11:01:31Z2022-08-16T11:01:31Z

    这是我对此类功能的实现。

    namespace Internal {
        inline uint32_t MultiplyAccumulate(uint32_t m1, uint32_t m2, uint32_t add, bool &overflow)
        {
            uint32_t ovf = 0;
            //В инструкции MUL набора инструкций thumb-2 поведение флага C не определено. Поскольку работаем с 
            //беззнаковыми числами, а слишком больших чисел не ожидается, можно заменить проверку переполнения флагом N.
            //После операции сложения проверяются флаги S и V. 
            asm volatile ("B calc \n"
                            "ovf: mov %6, #1 \n"
                            "B fin \n"
                            "calc: \n"
                            "muls %0, %1, %2 \n"
                            "BMI ovf \n"
                            "adds %3, %4, %5 \n"
                            "BVS ovf \n"
                            "BCS ovf \n"
                            "fin:"
                                :: "r"(m1), "r"(m1), "r"(m2), 
                                    "r"(m1), "r"(m1), "r"(add),
                                    "r"(ovf));
            overflow = (bool)ovf;
            return m1;
        }
    };
    
    /// \brief Преобразование массива символов в число
    /// \details Функция принимает массив в виде пары итераторов и
    /// выполняет преобразование его в число. 
    /// \param begin Итератор начала массива
    /// \param end Итератор конца массива
    template<typename Iterator>
    std::experimental::optional<uint32_t> ParseUint32(const Iterator begin, const Iterator end)
    {
        using value_type = typename std::iterator_traits<Iterator>::value_type;
        auto rbegin = std::make_reverse_iterator(end);
        auto rend = std::make_reverse_iterator(begin);
        
        uint32_t result = 0;
        int radix = 1;
        bool overflow = 0;
        for (auto it = rbegin; it != rend; it++, radix *= 10)
        {
            if (*it < '0' || *it > '9')
                return std::experimental::nullopt;
            uint32_t val = *it - '0';
            result = Internal::MultiplyAccumulate(val, radix, result, overflow);
            if (overflow)
            {
                return std::experimental::nullopt;
            }
        }
        return result;
    }
    

    其他类型可以类似地实现。

    • -1

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5