【问题标题】:Is it guaranteed that std::char_traits<char>::to_int_type(c) == static_cast<int>(c)?是否保证 std::char_traits<char>::to_int_type(c) == static_cast<int>(c)?
【发布时间】:2021-05-18 21:54:47
【问题描述】:

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][char.traits.specializations.char]的碎片吧:

  1. 对于每个inteto_char_type(e) 返回

    • c,如果​eq_­int_­type(e, ​to_­int_­type(c))为一些c

    • 其他一些未指定的值。

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

    • 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() 返回一个值 e 使得 !eq_int_type(e, to_int_type(c)) 对应所有 c

  4. eq(c, d) iff (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)从unsigned charint 的转换是保值的;

  • (属性 2)从 charunsigned char 的转换是双射的。

现在让我们验证要求:

  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) iff int(c) + 1 == int(d) + 1 iff @98765 (按属性 1)。 EOF 案例也很容易验证。

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

  4. 对于每对 charcdeq(c, d) iff (unsigned char) c == (unsigned char d)(按属性 2)。

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

【问题讨论】:

  • 不保证,实际上这两个是often different 的典型实现。
  • 不管怎样,我的阅读和你的一样; to_int_type 被允许执行任何可逆转换,没有任何东西说std::char_traits&lt;char&gt;::to_int_type(c) == static_cast&lt;int&gt;(c) 必须保持c 的任何值。
  • @IgorTandetnik 至少适合unsigned charchar 值似乎与常见的实现没有偏差——现在我必须计算我写的peek() == '\n' 的数量! (耸耸肩)

标签: c++ io language-lawyer istream char-traits


【解决方案1】:

这是否意味着这个实现符合要求,因此 std::cin.peek() == '\n' 没有做它应该做的事情?

我同意你的分析。这无法保证。

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


附:由于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_type 在 int 和 char 大小相同的系统上会有 UB,以防 c == INT_MAX,但您已经排除了那些具有假设大小的系统。

【讨论】:

  • 从技术上讲,UB 在标准库的实现中并不重要;)这个例子确实应该被调整。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多