当类型为 int8_t 且 base=2 时 std::from_chars 中的错误

1 c++ c++17

std::from_chars将位字符串 (base=2) 解析为有符号 8 位整数时失败,并出现一般错误,而std::stoi解析有符号 8 位整数时不会出现错误。

下面程序中的两个块都解析相同的位串。程序以调用std::abort第二个块中的第一个断言结束。std::stoi解析相同的位串没有错误。

// Compile: g++ -std=c++17 -O0 -g main.cc -o main
#include <string>
#include <cassert>
#include <charconv>
#include <cstdint>

int main()

{
    {
        std::string bits = "10011100";
        int base = 2;
        std::int8_t num = std::stoi(bits.c_str(), nullptr, base);
        assert(num == -100);
    }

    {
        // Bug found in std::from_chars when type is int8_t and base=2.
        std::string bits = "10011100";
        int base = 2;
        std::int8_t num;
        auto [ptr, ec] = std::from_chars(bits.data(),
                                         bits.data() + bits.size(),
                                         num,
                                         base);
        assert(ec == std::errc()); // Calls std::abort.
        assert(num == -100);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译后运行该程序的输出g++ -std=c++17 -O0 -g main.cc -o main

# ./main
main: main.cc:24: int main(): Assertion `ec == std::errc()' failed.
Aborted
Run Code Online (Sandbox Code Playgroud)

use*_*522 7

10011100二进制是156十进制。

有符号 8 位整数类型无法保存该值(最大值为127),因此std::from_chars会失败。

它不会失败std::stoi,因为该值156在 的范围内int(至少 16 位宽)。


如果您的目的是将这些位解释为 8 位整数值的二进制补码表示,那么您需要首先将其解析为 a uint8_t,然后转换为int8_t,假设 C++ 实现也使用二进制补码来表示int8_t。这在 C++20 中是强制的,但在 C++17 中不是强制的。如果实现不使用与您要解析的表示相同的表示,那么您需要手动进行转换。