是否保证 std::char_traits<char>::to_int_type(c) == static_cast<int>(c)?

Is it guaranteed that std::char_traits<char>::to_int_type(c) == static_cast<int>(c)?

问题How to use correctly the return value from std::cin.get() and std::cin.peek()?让我想知道是否保证

std::char_traits<char>::to_int_type(c) == static_cast<int>(c)

对于所有有效 charc


这在很多地方都会出现。例如,istream::peek 调用 streambuf::sgetc,后者使用 to_int_typechar 值转换为 int_type。现在,std::cin.peek() == '\n' 真的意味着下一个字符是 \n 吗?


这是我的分析。让我们收集 [char.traits.require] and [char.traits.specializations.char]:

的碎片
  1. 对于每个 inteto_char_type(e) returns

    • c,如果 ​eq_­int_­type(e, ​to_­int_­type(c)) 对于某些 c

    • 一些未指定的值。

  2. 对于每对 intefeq_­int_­type(e, f) returns

    • eq(c, d),如果 e == to_int_type(c)f == to_int_type(d) 对于某些 cd

    • true,如果e == eof()f == eof()

    • false, 如果 e == eof() xor f == eof();

    • 未另行说明。

  3. eof() returns 一个值 e 这样 !eq_int_type(e, to_int_type(c)) 对于所有 c.

  4. eq(c, d)当且仅当(unsigned char) c == (unsigned char) d.

现在,考虑这个假设的实现:(语法简化)

//          char: [-128, 127]
// unsigned char: [0, 255]
//           int: [-2^31, 2^31-1]

#define EOF INT_MIN

char to_char_type(int e) {
    return char(e - 1);
}

int to_int_type(char c) {
    return int(c) + 1;
}

bool eq(char c, char d) {
    return c == d;
}

bool eq_int_type(int c, int d) {
    return c == d;
}

int eof() {
    return EOF;
}

注意

现在让我们验证要求:

  1. 对于每个 inte,如果 ​eq_­int_­type(e, ​to_­int_­type(c)) 对于某些 c,则 e == int(c) + 1。因此,to_char_type(e) == char(int(c)) == c.

  2. 对于每对 intef,如果 e == to_int_type(c)f == to_int_type(d) 对于某些 cd,然后 eq_int_type(e, f) 当且仅当 int(c) + 1 == int(d) + 1 当且仅当 c == d (由 属性 1)。 EOF 案例也很容易验证。

  3. 对于每个 charcint(c) >= -128,所以 int(c) + 1 != EOF。因此,!eq_int_type(eof(), to_int_type(c)).

  4. 对于每对 charcdeq(c, d) 当且仅当 (unsigned char) c == (unsigned char d) (通过 属性 2).

这是否意味着此实现符合要求,因此 std::cin.peek() == '\n' 没有做它应该做的事情?我在分析中遗漏了什么吗?

Does that mean this implementation is conforming, and therefore std::cin.peek() == '\n' does not do what it is supposed to do?

我同意你的分析。这不能保证。

看来您必须使用 eq_­int_­type(std::cin.peek(), ​to_­int_­type('\n')) 来保证正确的结果。


P.S。由于 INT_MIN - 1 中的签名溢出,您的 ​to_­char_­type(EOF) 有未定义的行为。当然,在这种情况下该值未指定,但您仍然不能拥有 UB。这将是有效的:

char to_char_type(int e) {
    return e == EOF
         ? 0 // doesn't matter
         : char(e - 1);
}

to_int_typec == INT_MAX 的情况下,在 int 和 char 大小相同的系统上会有 UB,但您已经排除了那些具有假设大小的系统。